def evaluate_goto_definition(evaluator, context, leaf, prefer_stubs=False): if leaf.type == 'name': # In case of a name we can just use goto_definition which does all the # magic itself. if prefer_stubs: return evaluator.goto_stub_definitions(context, leaf) else: return evaluator.goto_definitions(context, leaf) parent = leaf.parent definitions = NO_CONTEXTS if parent.type == 'atom': definitions = context.eval_node(leaf.parent) elif parent.type == 'trailer': definitions = evaluate_call_of_leaf(context, leaf) elif isinstance(leaf, tree.Literal): return eval_atom(context, leaf) elif leaf.type in ('fstring_string', 'fstring_start', 'fstring_end'): return get_string_context_set(evaluator) if prefer_stubs: return definitions from jedi.evaluate.gradual.conversion import try_stubs_to_actual_context_set return try_stubs_to_actual_context_set( definitions, prefer_stub_to_compiled=True, )
def goto_stub_definitions(self, context, name): def_ = name.get_definition(import_name_always=True) if def_ is not None: type_ = def_.type is_classdef = type_ == 'classdef' if is_classdef or type_ == 'funcdef': if is_classdef: c = ClassContext(self, context, name.parent) else: c = FunctionContext.from_context(context, name.parent) return ContextSet([c]) if type_ == 'expr_stmt': is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return eval_expr_stmt(context, def_, name) if type_ == 'for_stmt': container_types = context.eval_node(def_.children[3]) cn = ContextualizedNode(context, def_.children[3]) for_types = iterate_contexts(container_types, cn) c_node = ContextualizedName(context, name) return check_tuple_assignments(self, c_node, for_types) if type_ in ('import_from', 'import_name'): return imports.infer_import(context, name) else: result = self._follow_error_node_imports_if_possible(context, name) if result is not None: return result return helpers.evaluate_call_of_leaf(context, name)
def _analysis(self): self._evaluator.is_analysis = True module_node = self._get_module_node() self._evaluator.analysis_modules = [module_node] try: for node in get_executable_nodes(module_node): context = self._get_module().create_context(node) if node.type in ('funcdef', 'classdef'): # Resolve the decorators. tree_name_to_contexts(self._evaluator, context, node.children[1]) elif isinstance(node, tree.Import): import_names = set(node.get_defined_names()) if node.is_nested(): import_names |= set(path[-1] for path in node.get_paths()) for n in import_names: imports.infer_import(context, n) elif node.type == 'expr_stmt': types = context.eval_node(node) for testlist in node.children[:-1:2]: # Iterate tuples. unpack_tuple_to_dict(context, types, testlist) else: if node.type == 'name': defs = self._evaluator.goto_definitions(context, node) else: defs = evaluate_call_of_leaf(context, node) try_iter_content(defs) self._evaluator.reset_recursion_limitations() ana = [a for a in self._evaluator.analysis if self.path == a.path] return sorted(set(ana), key=lambda x: x.line) finally: self._evaluator.is_analysis = False
def _analysis(self): self._evaluator.is_analysis = True self._evaluator.analysis_modules = [self._module_node] module = self._get_module() try: for node in get_executable_nodes(self._module_node): context = module.create_context(node) if node.type in ('funcdef', 'classdef'): # Resolve the decorators. tree_name_to_contexts(self._evaluator, context, node.children[1]) elif isinstance(node, tree.Import): import_names = set(node.get_defined_names()) if node.is_nested(): import_names |= set(path[-1] for path in node.get_paths()) for n in import_names: imports.infer_import(context, n) elif node.type == 'expr_stmt': types = context.eval_node(node) for testlist in node.children[:-1:2]: # Iterate tuples. unpack_tuple_to_dict(context, types, testlist) else: if node.type == 'name': defs = self._evaluator.goto_definitions(context, node) else: defs = evaluate_call_of_leaf(context, node) try_iter_content(defs) self._evaluator.reset_recursion_limitations() ana = [a for a in self._evaluator.analysis if self.path == a.path] return sorted(set(ana), key=lambda x: x.line) finally: self._evaluator.is_analysis = False
def _trailer_completions(self, previous_leaf): user_context = get_user_scope(self._module_context, self._position) evaluation_context = self._evaluator.create_context( self._module_context, previous_leaf ) contexts = evaluate_call_of_leaf(evaluation_context, previous_leaf) completion_names = [] debug.dbg('trailer completion contexts: %s', contexts, color='MAGENTA') for context in contexts: for filter in context.get_filters( search_global=False, origin_scope=user_context.tree_node): completion_names += filter.values() for context in contexts: if not context.is_stub(): continue actual_contexts = stub_to_actual_context_set(context, ignore_compiled=True) for c in actual_contexts: for filter in c.get_filters( search_global=False, origin_scope=user_context.tree_node): completion_names += filter.values() return completion_names
def _trailer_completions(self, previous_leaf): user_context = get_user_scope(self._module_context, self._position) evaluation_context = self._evaluator.create_context( self._module_context, previous_leaf) contexts = evaluate_call_of_leaf(evaluation_context, previous_leaf) completion_names = [] debug.dbg('trailer completion contexts: %s', contexts) for context in contexts: for filter in context.get_filters( search_global=False, origin_scope=user_context.tree_node): completion_names += filter.values() return completion_names
def _trailer_completions(self, previous_leaf): user_context = get_user_scope(self._module_context, self._position) evaluation_context = self._evaluator.create_context( self._module_context, previous_leaf ) contexts = evaluate_call_of_leaf(evaluation_context, previous_leaf) completion_names = [] debug.dbg('trailer completion contexts: %s', contexts) for context in contexts: for filter in context.get_filters( search_global=False, origin_scope=user_context.tree_node): completion_names += filter.values() return completion_names
def evaluate_goto_definition(evaluator, context, leaf): if leaf.type == 'name': # In case of a name we can just use goto_definition which does all the # magic itself. return evaluator.goto_definitions(context, leaf) parent = leaf.parent if parent.type == 'atom': return context.eval_node(leaf.parent) elif parent.type == 'trailer': return evaluate_call_of_leaf(context, leaf) elif isinstance(leaf, tree.Literal): return context.evaluator.eval_atom(context, leaf) return []
def evaluate_goto_definition(evaluator, context, leaf): if leaf.type == 'name': # In case of a name we can just use goto_definition which does all the # magic itself. return evaluator.goto_definitions(context, leaf) parent = leaf.parent if parent.type == 'atom': return context.eval_node(leaf.parent) elif parent.type == 'trailer': return evaluate_call_of_leaf(context, leaf) elif isinstance(leaf, tree.Literal): return context.evaluator.eval_atom(context, leaf) return []
def evaluate_goto_definition(evaluator, context, leaf): if leaf.type == 'name': # In case of a name we can just use goto_definition which does all the # magic itself. return evaluator.goto_definitions(context, leaf) parent = leaf.parent definitions = NO_CONTEXTS if parent.type == 'atom': definitions = context.eval_node(leaf.parent) elif parent.type == 'trailer': definitions = evaluate_call_of_leaf(context, leaf) elif isinstance(leaf, tree.Literal): return eval_atom(context, leaf) elif leaf.type in ('fstring_string', 'fstring_start', 'fstring_end'): return get_string_context_set(evaluator) return definitions
def goto_definitions(self, context, name): def_ = name.get_definition() is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: if name.parent.type == 'classdef' and name.parent.name == name: return [er.ClassContext(self, name.parent, context)] elif name.parent.type == 'funcdef': return [er.FunctionContext(self, context, name.parent)] elif name.parent.type == 'file_input': raise NotImplementedError if def_.type == 'expr_stmt' and name in def_.get_defined_names(): return self.eval_statement(context, def_, name) elif def_.type == 'for_stmt': container_types = self.eval_element(context, def_.children[3]) for_types = iterable.py__iter__types(self, container_types, def_.children[3]) return finder.check_tuple_assignments(self, for_types, name) elif def_.type in ('import_from', 'import_name'): return imports.infer_import(context, name) return helpers.evaluate_call_of_leaf(context, name)
def goto_definitions(self, context, name): def_ = name.get_definition() is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: if name.parent.type == 'classdef' and name.parent.name == name: return [er.ClassContext(self, name.parent, context)] elif name.parent.type == 'funcdef': return [er.FunctionContext(self, context, name.parent)] elif name.parent.type == 'file_input': raise NotImplementedError if def_.type == 'expr_stmt' and name in def_.get_defined_names(): return self.eval_statement(context, def_, name) elif def_.type == 'for_stmt': container_types = self.eval_element(context, def_.children[3]) cn = ContextualizedNode(context, def_.children[3]) for_types = iterable.py__iter__types(self, container_types, cn) c_node = ContextualizedName(context, name) return finder.check_tuple_assignments(self, c_node, for_types) elif def_.type in ('import_from', 'import_name'): return imports.infer_import(context, name) return helpers.evaluate_call_of_leaf(context, name)
def goto_definitions(self, context, name): def_ = name.get_definition(import_name_always=True) if def_ is not None: type_ = def_.type if type_ == 'classdef': return [ClassContext(self, context, name.parent)] elif type_ == 'funcdef': return [FunctionContext(self, context, name.parent)] if type_ == 'expr_stmt': is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return eval_expr_stmt(context, def_, name) if type_ == 'for_stmt': container_types = context.eval_node(def_.children[3]) cn = ContextualizedNode(context, def_.children[3]) for_types = iterate_contexts(container_types, cn) c_node = ContextualizedName(context, name) return check_tuple_assignments(self, c_node, for_types) if type_ in ('import_from', 'import_name'): return imports.infer_import(context, name) return helpers.evaluate_call_of_leaf(context, name)
def _check_array_additions(context, sequence): """ Checks if a `Array` has "add" (append, insert, extend) statements: >>> a = [""] >>> a.append(1) """ from jedi.evaluate import arguments debug.dbg('Dynamic array search for %s' % sequence, color='MAGENTA') module_context = context.get_root_context() if not settings.dynamic_array_additions or isinstance( module_context, compiled.CompiledObject): debug.dbg('Dynamic array search aborted.', color='MAGENTA') return ContextSet() def find_additions(context, arglist, add_name): params = list( arguments.TreeArguments(context.evaluator, context, arglist).unpack()) result = set() if add_name in ['insert']: params = params[1:] if add_name in ['append', 'add', 'insert']: for key, whatever in params: result.add(whatever) elif add_name in ['extend', 'update']: for key, lazy_context in params: result |= set(lazy_context.infer().iterate()) return result temp_param_add, settings.dynamic_params_for_other_modules = \ settings.dynamic_params_for_other_modules, False is_list = sequence.name.string_name == 'list' search_names = (['append', 'extend', 'insert'] if is_list else ['add', 'update']) added_types = set() for add_name in search_names: try: possible_names = module_context.tree_node.get_used_names( )[add_name] except KeyError: continue else: for name in possible_names: context_node = context.tree_node if not (context_node.start_pos < name.start_pos < context_node.end_pos): continue trailer = name.parent power = trailer.parent trailer_pos = power.children.index(trailer) try: execution_trailer = power.children[trailer_pos + 1] except IndexError: continue else: if execution_trailer.type != 'trailer' \ or execution_trailer.children[0] != '(' \ or execution_trailer.children[1] == ')': continue random_context = context.create_context(name) with recursion.execution_allowed(context.evaluator, power) as allowed: if allowed: found = evaluate_call_of_leaf(random_context, name, cut_own_trailer=True) if sequence in found: # The arrays match. Now add the results added_types |= find_additions( random_context, execution_trailer.children[1], add_name) # reset settings settings.dynamic_params_for_other_modules = temp_param_add debug.dbg('Dynamic array result %s' % added_types, color='MAGENTA') return added_types
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 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, 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, 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, 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 _check_array_additions(context, sequence): """ Checks if a `Array` has "add" (append, insert, extend) statements: >>> a = [""] >>> a.append(1) """ from jedi.evaluate import param debug.dbg('Dynamic array search for %s' % sequence, color='MAGENTA') module_context = context.get_root_context() if not settings.dynamic_array_additions or isinstance(module_context, compiled.CompiledObject): debug.dbg('Dynamic array search aborted.', color='MAGENTA') return set() def find_additions(context, arglist, add_name): params = list(param.TreeArguments(context.evaluator, context, arglist).unpack()) result = set() if add_name in ['insert']: params = params[1:] if add_name in ['append', 'add', 'insert']: for key, lazy_context in params: result.add(lazy_context) elif add_name in ['extend', 'update']: for key, lazy_context in params: result |= set(py__iter__(context.evaluator, lazy_context.infer())) return result temp_param_add, settings.dynamic_params_for_other_modules = \ settings.dynamic_params_for_other_modules, False is_list = sequence.name.string_name == 'list' search_names = (['append', 'extend', 'insert'] if is_list else ['add', 'update']) added_types = set() for add_name in search_names: try: possible_names = module_context.tree_node.used_names[add_name] except KeyError: continue else: for name in possible_names: context_node = context.tree_node if not (context_node.start_pos < name.start_pos < context_node.end_pos): continue trailer = name.parent power = trailer.parent trailer_pos = power.children.index(trailer) try: execution_trailer = power.children[trailer_pos + 1] except IndexError: continue else: if execution_trailer.type != 'trailer' \ or execution_trailer.children[0] != '(' \ or execution_trailer.children[1] == ')': continue random_context = context.create_context(name) with recursion.execution_allowed(context.evaluator, power) as allowed: if allowed: found = helpers.evaluate_call_of_leaf( random_context, name, cut_own_trailer=True ) if sequence in found: # The arrays match. Now add the results added_types |= find_additions( random_context, execution_trailer.children[1], add_name ) # reset settings settings.dynamic_params_for_other_modules = temp_param_add debug.dbg('Dynamic array result %s' % added_types, color='MAGENTA') return added_types