def _scope_copy(self, scope): raise NotImplementedError """ Copies a scope (e.g. `if foo:`) in an execution """ if scope != self.base.base_func: # Just make sure the parents been copied. self._scope_copy(scope.parent) helpers.deep_ast_copy(scope, self._copy_dict)
def _eval_node(self, index=0): """ The first part `x + 1` of the list comprehension: [x + 1 for x in foo] """ comp_for = self._get_comp_for() # For nested comprehensions we need to search the last one. last_comp = list(comp_for.get_comp_fors())[-1] return helpers.deep_ast_copy(self._get_comprehension().children[index], parent=last_comp)
def _copy_list(self, lst): """ Copies a list attribute of a parser Function. Copying is very expensive, because it is something like `copy.deepcopy`. However, these copied objects can be used for the executions, as if they were in the execution. """ objects = [] for element in lst: self._scope_copy(element.parent) copied = helpers.deep_ast_copy(element, self._copy_dict) objects.append(copied) return objects
def __init__(self, evaluator, base, *args, **kwargs): super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs) self._copy_dict = {} funcdef = base.base_func if isinstance(funcdef, mixed.MixedObject): # The extra information in mixed is not needed anymore. We can just # unpack it and give it the tree object. funcdef = funcdef.definition # Just overwrite the old version. We don't need it anymore. funcdef = helpers.deep_ast_copy(funcdef, new_elements=self._copy_dict) for child in funcdef.children: if child.type not in ('operator', 'keyword'): # Not all nodes are properly copied by deep_ast_copy. child.parent = self self.children = funcdef.children self.names_dict = funcdef.names_dict
def _eval_node(self, index=0): """ The first part `x + 1` of the list comprehension: [x + 1 for x in foo] """ comp_for = self._get_comp_for() # For nested comprehensions we need to search the last one. from jedi.evaluate.representation import InstanceElement node = self._get_comprehension().children[index] if isinstance(node, InstanceElement): # This seems to be a strange case that I haven't found a way to # write tests against. However since it's my new goal to get rid of # InstanceElement anyway, I don't care. node = node.var last_comp = list(comp_for.get_comp_fors())[-1] return helpers.deep_ast_copy(node, parent=last_comp)
def eval_node(self): """ The first part `x + 1` of the list comprehension: [x + 1 for x in foo] """ comprehension = self._atom.children[1] # For nested comprehensions we need to search the last one. last = comprehension.children[-1] last_comp = comprehension.children[1] while True: if isinstance(last, tree.CompFor): last_comp = last elif not tree.is_node(last, 'comp_if'): break last = last.children[-1] return helpers.deep_ast_copy(comprehension.children[0], parent=last_comp)
def __init__(self, evaluator, base, *args, **kwargs): super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs) self._copy_dict = {} new_func = helpers.deep_ast_copy(base.base_func, self, self._copy_dict) self.children = new_func.children self.names_dict = new_func.names_dict
def goto(self, context, name): definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type if type_ == 'expr_stmt': # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return [TreeNameDefinition(context, name)] elif type_ == 'param': return [ParamName(context, name)] elif type_ in ('funcdef', 'classdef'): return [TreeNameDefinition(context, name)] elif type_ in ('import_from', 'import_name'): module_names = imports.infer_import(context, name, is_goto=True) return module_names else: contexts = self._follow_error_node_imports_if_possible( context, name) if contexts is not None: return [context.name for context in contexts] par = name.parent node_type = par.type if node_type == 'argument' and par.children[1] == '=' and par.children[ 0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': context_set = context.eval_node(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] if to_evaluate[0] == 'await': to_evaluate.pop(0) context_set = context.eval_node(to_evaluate[0]) for trailer in to_evaluate[1:]: context_set = eval_trailer(context, context_set, trailer) param_names = [] for context in context_set: for signature in context.get_signatures(): for param_name in signature.get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif node_type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = context.eval_node(new_dotted) return unite( value.py__getattribute__( name, name_context=context, is_goto=True) for value in values) if node_type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return values.py__getattribute__(name, name_context=context, is_goto=True) else: stmt = tree.search_ancestor(name, 'expr_stmt', 'lambdef') or name if stmt.type == 'lambdef': stmt = name return context.py__getattribute__(name, position=stmt.start_pos, search_global=True, is_goto=True)
def goto(self, context, name): definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type if type_ == 'expr_stmt': # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return [TreeNameDefinition(context, name)] elif type_ == 'param': return [ParamName(context, name)] elif type_ in ('funcdef', 'classdef'): return [TreeNameDefinition(context, name)] elif type_ in ('import_from', 'import_name'): module_names = imports.infer_import(context, name, is_goto=True) return module_names par = name.parent node_type = par.type if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': context_set = context.eval_node(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] if to_evaluate[0] == 'await': to_evaluate.pop(0) context_set = context.eval_node(to_evaluate[0]) for trailer in to_evaluate[1:]: context_set = eval_trailer(context, context_set, trailer) param_names = [] for context in context_set: try: get_param_names = context.get_param_names except AttributeError: pass else: for param_name in get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif node_type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = context.eval_node(new_dotted) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) if node_type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) else: stmt = tree.search_ancestor( name, 'expr_stmt', 'lambdef' ) or name if stmt.type == 'lambdef': stmt = name return context.py__getattribute__( name, position=stmt.start_pos, search_global=True, is_goto=True )
def goto(self, name): def resolve_implicit_imports(names): for name in names: if isinstance(name.parent, helpers.FakeImport): # Those are implicit imports. s = imports.ImportWrapper(self, name) for n in s.follow(is_goto=True): yield n else: yield name stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[ 0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': types = self.eval_element(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] types = self.eval_element(to_evaluate[0]) for trailer in to_evaluate[1:]: types = self.eval_trailer(types, trailer) param_names = [] for typ in types: try: params = typ.params except AttributeError: pass else: param_names += [ param.name for param in params if param.name.value == name.value ] return param_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 # a name it's something you can "goto" again. return [name] elif isinstance( par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [name] elif isinstance(stmt, tree.Import): modules = imports.ImportWrapper(self, name).follow(is_goto=True) return list(resolve_implicit_imports(modules)) elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] types = self.eval_element(new_dotted) return resolve_implicit_imports( iterable.unite( 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] == '.': call = helpers.call_of_leaf(name, cut_own_trailer=True) types = self.eval_element(call) return resolve_implicit_imports( iterable.unite( self.find_types(typ, name, is_goto=True) for typ in types)) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = name return self.find_types(scope, name, stmt.start_pos, search_global=True, is_goto=True)
def goto(self, name): def resolve_implicit_imports(names): for name in names: if isinstance(name.parent, helpers.FakeImport): # Those are implicit imports. s = imports.ImportWrapper(self, name) for n in s.follow(is_goto=True): yield n else: yield name stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': types = self.eval_element(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] types = self.eval_element(to_evaluate[0]) for trailer in to_evaluate[1:]: types = self.eval_trailer(types, trailer) param_names = [] for typ in types: try: params = typ.params except AttributeError: pass else: param_names += [param.name for param in params if param.name.value == name.value] return param_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 # a name it's something you can "goto" again. return [name] elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [name] elif isinstance(stmt, tree.Import): modules = imports.ImportWrapper(self, name).follow(is_goto=True) return list(resolve_implicit_imports(modules)) elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] types = self.eval_element(new_dotted) return resolve_implicit_imports(iterable.unite( 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] == '.': call = helpers.call_of_leaf(name, cut_own_trailer=True) types = self.eval_element(call) return resolve_implicit_imports(iterable.unite( self.find_types(typ, name, is_goto=True) for typ in types )) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = name return self.find_types(scope, name, stmt.start_pos, search_global=True, is_goto=True)
def goto(self, context, name): stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': types = self.eval_element(context, trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] types = self.eval_element(context, to_evaluate[0]) for trailer in to_evaluate[1:]: types = self.eval_trailer(context, types, trailer) param_names = [] for typ in types: try: get_param_names = typ.get_param_names except AttributeError: pass else: for param_name in get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif par.type == 'expr_stmt' and name in par.get_defined_names(): # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. return [TreeNameDefinition(context, name)] elif par.type == 'param' and par.name: return [ParamName(context, name)] elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [TreeNameDefinition(context, name)] elif isinstance(stmt, tree.Import): module_names = imports.infer_import(context, name, is_goto=True) return module_names elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = self.eval_element(context, new_dotted) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) if par.type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = name return context.py__getattribute__( name, position=stmt.start_pos, search_global=True, is_goto=True )
def goto(self, stmt, call_path): if isinstance(stmt, pr.Import): # Nowhere to goto for aliases if stmt.alias == call_path[0]: return [call_path[0]] names = stmt.get_all_import_names() if stmt.alias: names = names[:-1] # Filter names that are after our Name removed_names = len(names) - names.index(call_path[0]) - 1 i = imports.ImportWrapper(self, stmt, kill_count=removed_names, nested_resolve=True) return i.follow(is_goto=True) # Return the name defined in the call_path, if it's part of the # statement name definitions. Only return, if it's one name and one # name only. Otherwise it's a mixture between a definition and a # reference. In this case it's just a definition. So we stay on it. if len(call_path) == 1 and isinstance(call_path[0], pr.Name) \ and call_path[0] in stmt.get_defined_names(): # Named params should get resolved to their param definitions. if pr.Array.is_type(stmt.parent, pr.Array.TUPLE, pr.Array.NOARRAY) \ and stmt.parent.previous: call = deep_ast_copy(stmt.parent.previous) # We have made a copy, so we're fine to change it. call.next = None while call.previous is not None: call = call.previous param_names = [] named_param_name = stmt.get_defined_names()[0] for typ in self.eval_call(call): if isinstance(typ, er.Class): params = [] for init_method in typ.py__getattribute__('__init__'): params += init_method.params else: params = typ.params for param in params: if unicode(param.get_name()) == unicode(named_param_name): param_names.append(param.get_name()) return param_names return [call_path[0]] scope = stmt.get_parent_scope() pos = stmt.start_pos first_part, search_name_part = call_path[:-1], call_path[-1] if first_part: scopes = self.eval_call_path(iter(first_part), scope, pos) search_global = False pos = None else: scopes = [scope] search_global = True follow_res = [] for s in scopes: follow_res += self.find_types(s, search_name_part, pos, search_global=search_global, is_goto=True) return follow_res
def goto(self, context, name): stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[ 0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': types = self.eval_element(context, trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] types = self.eval_element(context, to_evaluate[0]) for trailer in to_evaluate[1:]: types = self.eval_trailer(context, types, trailer) param_names = [] for typ in types: try: get_param_names = typ.get_param_names except AttributeError: pass else: for param_name in get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif par.type == 'expr_stmt' and name in par.get_defined_names(): # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. return [TreeNameDefinition(context, name)] elif par.type == 'param' and par.name: return [ParamName(context, name)] elif isinstance( par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [TreeNameDefinition(context, name)] elif isinstance(stmt, tree.Import): module_names = imports.infer_import(context, name, is_goto=True) return module_names elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = self.eval_element(context, new_dotted) return unite( value.py__getattribute__( name, name_context=context, is_goto=True) for value in values) if par.type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return unite( value.py__getattribute__( name, name_context=context, is_goto=True) for value in values) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = name return context.py__getattribute__(name, position=stmt.start_pos, search_global=True, is_goto=True)
def _scope_copy(self, scope): """ Copies a scope (e.g. `if foo:`) in an execution """ if scope != self.base.base_func: # Just make sure the parents been copied. self._scope_copy(scope.parent) helpers.deep_ast_copy(scope, self._copy_dict)