def _follow_param(evaluator, params, index): try: key, values = list(params.unpack())[index] except IndexError: return [] else: return iterable.unite(evaluator.eval_element(v) for v in values)
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 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': for i, t in enumerate(trailer.parent.children): if t == 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, pr.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, (pr.Param, pr.Function, pr.Class)) and par.name is name: return [name] elif isinstance(stmt, pr.Import): return imports.ImportWrapper(self, name).follow(is_goto=True) scope = name.get_parent_scope() if pr.is_node(name.parent, 'trailer'): call = call_of_name(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: return self.find_types(scope, name, stmt.start_pos, search_global=True, is_goto=True)
def eval_element(self, element): if isinstance(element, iterable.AlreadyEvaluated): return list(element) elif isinstance(element, iterable.MergedNodes): return iterable.unite(self.eval_element(e) for e in element) debug.dbg('eval_element %s@%s', element, element.start_pos) if isinstance(element, (pr.Name, pr.Literal)) or pr.is_node(element, 'atom'): return self._eval_atom(element) elif isinstance(element, pr.Keyword): # For False/True/None if element.value in ('False', 'True', 'None'): return [compiled.builtin.get_by_name(element.value)] else: return [] elif element.isinstance(pr.Lambda): return [er.LambdaWrapper(self, element)] elif element.isinstance(er.LambdaWrapper): return [element] # TODO this is no real evaluation. elif element.type == 'expr_stmt': return self.eval_statement(element) elif element.type == 'power': types = self._eval_atom(element.children[0]) for trailer in element.children[1:]: if trailer == '**': # has a power operation. raise NotImplementedError types = self.eval_trailer(types, trailer) return types elif element.type in ( 'testlist_star_expr', 'testlist', ): # The implicit tuple in statements. return [iterable.ImplicitTuple(self, element)] elif element.type in ('not_test', 'factor'): types = self.eval_element(element.children[-1]) for operator in element.children[:-1]: types = list(precedence.factor_calculate( self, types, operator)) return types elif element.type == 'test': # `x if foo else y` case. return (self.eval_element(element.children[0]) + self.eval_element(element.children[-1])) elif element.type == 'operator': # Must be an ellipsis, other operators are not evaluated. return [] # Ignore for now. elif element.type == 'dotted_name': types = self._eval_atom(element.children[0]) for next_name in element.children[2::2]: types = list( chain.from_iterable( self.find_types(typ, next_name) for typ in types)) return types else: return precedence.calculate_children(self, element.children)
def eval_element(self, element): if isinstance(element, iterable.AlreadyEvaluated): return list(element) elif isinstance(element, iterable.MergedNodes): return iterable.unite(self.eval_element(e) for e in element) debug.dbg('eval_element %s@%s', element, element.start_pos) if isinstance(element, (pr.Name, pr.Literal)) or pr.is_node(element, 'atom'): return self._eval_atom(element) elif isinstance(element, pr.Keyword): # For False/True/None if element.value in ('False', 'True', 'None'): return [compiled.builtin.get_by_name(element.value)] else: return [] elif element.isinstance(pr.Lambda): return [er.LambdaWrapper(self, element)] elif element.isinstance(er.LambdaWrapper): return [element] # TODO this is no real evaluation. elif element.type == 'expr_stmt': return self.eval_statement(element) elif element.type == 'power': types = self._eval_atom(element.children[0]) for trailer in element.children[1:]: if trailer == '**': # has a power operation. raise NotImplementedError types = self.eval_trailer(types, trailer) return types elif element.type in ('testlist_star_expr', 'testlist',): # The implicit tuple in statements. return [iterable.ImplicitTuple(self, element)] elif element.type in ('not_test', 'factor'): types = self.eval_element(element.children[-1]) for operator in element.children[:-1]: types = list(precedence.factor_calculate(self, types, operator)) return types elif element.type == 'test': # `x if foo else y` case. return (self.eval_element(element.children[0]) + self.eval_element(element.children[-1])) elif element.type == 'operator': # Must be an ellipsis, other operators are not evaluated. return [] # Ignore for now. elif element.type == 'dotted_name': types = self._eval_atom(element.children[0]) for next_name in element.children[2::2]: types = list(chain.from_iterable(self.find_types(typ, next_name) for typ in types)) return types else: return precedence.calculate_children(self, element.children)
def get_return_types(self, check_yields=False): func = self.base if func.isinstance(LambdaWrapper): return self._evaluator.eval_element(self.children[-1]) if func.listeners: # Feed the listeners, with the params. for listener in func.listeners: listener.execute(self._get_params()) # If we do have listeners, that means that there's not a regular # execution ongoing. In this case Jedi is interested in the # inserted params, not in the actual execution of the function. return set() if check_yields: types = set() returns = self.yields else: returns = self.returns types = set(docstrings.find_return_types(self._evaluator, func)) types |= set(pep0484.find_return_types(self._evaluator, func)) for r in returns: check = flow_analysis.break_check(self._evaluator, self, r) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: if check_yields: types |= iterable.unite(self._eval_yield(r)) else: types |= self._evaluator.eval_element(r.children[1]) if check is flow_analysis.REACHABLE: debug.dbg('Return reachable: %s', r) break return types
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 eval_element(self, element): if isinstance(element, iterable.AlreadyEvaluated): return set(element) elif isinstance(element, iterable.MergedNodes): return iterable.unite(self.eval_element(e) for e in element) if_stmt = element.get_parent_until( (tree.IfStmt, tree.ForStmt, tree.IsScope)) predefined_if_name_dict = self.predefined_if_name_dict_dict.get( if_stmt) if predefined_if_name_dict is None and isinstance( if_stmt, tree.IfStmt): if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # predefined_if_name_dict_dict is filled, we stop. # We don't want to check the if stmt itself, it's just about # the content. if element.start_pos > if_stmt_test.end_pos: # Now we need to check if the names in the if_stmt match the # names in the suite. if_names = helpers.get_names_of_node(if_stmt_test) element_names = helpers.get_names_of_node(element) str_element_names = [str(e) for e in element_names] if any(str(i) in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(if_name) # Every name that has multiple different definitions # causes the complexity to rise. The complexity should # never fall below 1. if len(definitions) > 1: if len(name_dicts) * len(definitions) > 16: debug.dbg( 'Too many options for if branch evaluation %s.', if_stmt) # There's only a certain amount of branches # Jedi can evaluate, otherwise it will take to # long. name_dicts = [{}] break original_name_dicts = list(name_dicts) name_dicts = [] for definition in definitions: new_name_dicts = list(original_name_dicts) for i, name_dict in enumerate(new_name_dicts): new_name_dicts[i] = name_dict.copy() new_name_dicts[i][str(if_name)] = [ definition ] name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[str(if_name)] = definitions if len(name_dicts) > 1: result = set() for name_dict in name_dicts: self.predefined_if_name_dict_dict[if_stmt] = name_dict try: result |= self._eval_element_not_cached(element) finally: del self.predefined_if_name_dict_dict[if_stmt] return result else: return self._eval_element_if_evaluated(element) return self._eval_element_cached(element) else: if predefined_if_name_dict: return self._eval_element_not_cached(element) else: return self._eval_element_if_evaluated(element) return self._eval_element_cached(element)
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 eval_element(self, element): if isinstance(element, iterable.AlreadyEvaluated): return set(element) elif isinstance(element, iterable.MergedNodes): return iterable.unite(self.eval_element(e) for e in element) if_stmt = element.get_parent_until((tree.IfStmt, tree.ForStmt, tree.IsScope)) predefined_if_name_dict = self.predefined_if_name_dict_dict.get(if_stmt) if predefined_if_name_dict is None and isinstance(if_stmt, tree.IfStmt): if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # predefined_if_name_dict_dict is filled, we stop. # We don't want to check the if stmt itself, it's just about # the content. if element.start_pos > if_stmt_test.end_pos: # Now we need to check if the names in the if_stmt match the # names in the suite. if_names = helpers.get_names_of_node(if_stmt_test) element_names = helpers.get_names_of_node(element) str_element_names = [str(e) for e in element_names] if any(str(i) in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(if_name) # Every name that has multiple different definitions # causes the complexity to rise. The complexity should # never fall below 1. if len(definitions) > 1: if len(name_dicts) * len(definitions) > 16: debug.dbg('Too many options for if branch evaluation %s.', if_stmt) # There's only a certain amount of branches # Jedi can evaluate, otherwise it will take to # long. name_dicts = [{}] break original_name_dicts = list(name_dicts) name_dicts = [] for definition in definitions: new_name_dicts = list(original_name_dicts) for i, name_dict in enumerate(new_name_dicts): new_name_dicts[i] = name_dict.copy() new_name_dicts[i][str(if_name)] = [definition] name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[str(if_name)] = definitions if len(name_dicts) > 1: result = set() for name_dict in name_dicts: self.predefined_if_name_dict_dict[if_stmt] = name_dict try: result |= self._eval_element_not_cached(element) finally: del self.predefined_if_name_dict_dict[if_stmt] return result else: return self._eval_element_if_evaluated(element) return self._eval_element_cached(element) else: if predefined_if_name_dict: return self._eval_element_not_cached(element) else: return self._eval_element_if_evaluated(element) return self._eval_element_cached(element)