def find_usages_in_node(node, global_encountered=False): names = [] if isinstance(node, tree.BaseNode): if parser_utils.is_scope(node): global_encountered = False if node in searched_scopes: return names searched_scopes.add(node) if isinstance(node, tree.Function): d = self._get_def_from_function_params(node, name) if d and d != definition: return [] for c in node.children: dot_names = self._get_dot_names(c) if len(dot_names) > 1 and dot_names[1].value == name.value: continue sub_result = find_usages_in_node(c, global_encountered=global_encountered) if sub_result is None: if not parser_utils.is_scope(node): return ( None if definition and node != parser_utils.get_parent_scope(definition) else [definition] ) else: sub_result = [] names.extend(sub_result) if self._is_global_stmt_with_name(c, name.value): global_encountered = True elif isinstance(node, tree.Name) and node.value == name.value: if definition and definition != node: if self._is_name_function_definition(node): if isinstance( parser_utils.get_parent_scope(parser_utils.get_parent_scope(node)), tree.Class, ): return [] else: return None if ( node.is_definition() and not global_encountered and ( is_function_definition or parser_utils.get_parent_scope(node) != parser_utils.get_parent_scope(definition) ) ): return None if self._is_name_function_definition(definition) and isinstance( parser_utils.get_parent_scope(parser_utils.get_parent_scope(definition)), tree.Class, ): return None names.append(node) return names
def filter_name(self, filters): """ Searches names that are defined in a scope (the different ``filters``), until a name fits. """ names = [] if self._context.predefined_names: # TODO is this ok? node might not always be a tree.Name node = self._name while node is not None and not is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for"): try: name_dict = self._context.predefined_names[node] types = name_dict[self._string_name] except KeyError: continue else: self._found_predefined_types = types break for filter in filters: names = filter.get(self._string_name) if names: break debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name, self._context, names, self._position) return list(names)
def filter_name(self, filters): """ Searches names that are defined in a scope (the different ``filters``), until a name fits. """ names = [] if self._context.predefined_names: # TODO is this ok? node might not always be a tree.Name node = self._name while node is not None and not is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for"): try: name_dict = self._context.predefined_names[node] types = name_dict[self._string_name] except KeyError: continue else: self._found_predefined_types = types break for filter in filters: names = filter.get(self._string_name) if names: break debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name, self._context, names, self._position) return list(names)
def is_scope(node): try: # jedi 0.11 from jedi import parser_utils return parser_utils.is_scope(node) except ImportError: # Older versions return node.is_scope()
def py__getattribute__(self, name_or_str, name_context=None, position=None, analysis_errors=True): """ :param position: Position of the last statement -> tuple of line, column """ if name_context is None: name_context = self names = self.goto(name_or_str, position) string_name = name_or_str.value if isinstance(name_or_str, Name) else name_or_str # This paragraph is currently needed for proper branch type inference # (static analysis). found_predefined_types = None if self.predefined_names and isinstance(name_or_str, Name): node = name_or_str while node is not None and not parser_utils.is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for", 'sync_comp_for'): try: name_dict = self.predefined_names[node] types = name_dict[string_name] except KeyError: continue else: found_predefined_types = types break if found_predefined_types is not None and names: from jedi.inference import flow_analysis check = flow_analysis.reachability_check( context=self, value_scope=self.tree_node, node=name_or_str, ) if check is flow_analysis.UNREACHABLE: values = NO_VALUES else: values = found_predefined_types else: values = ValueSet.from_sets(name.infer() for name in names) if not names and not values and analysis_errors: if isinstance(name_or_str, Name): from jedi.inference import analysis message = ("NameError: name '%s' is not defined." % string_name) analysis.add(name_context, 'name-error', name_or_str, message) debug.dbg('context.names_to_types: %s -> %s', names, values) if values: return values return self._check_for_additional_knowledge(name_or_str, name_context, position)
def create_context(self, base_context, node, node_is_context=False, node_is_object=False): def parent_scope(node): while True: node = node.parent if parser_utils.is_scope(node): return node elif node.type in ('argument', 'testlist_comp'): if node.children[1].type == 'comp_for': return node.children[1] elif node.type == 'dictorsetmaker': for n in node.children[1:4]: # In dictionaries it can be pretty much anything. if n.type == 'comp_for': return n def from_scope_node(scope_node, is_nested=True, node_is_object=False): if scope_node == base_node: return base_context is_funcdef = scope_node.type in ('funcdef', 'lambdef') parent_scope = parser_utils.get_parent_scope(scope_node) parent_context = from_scope_node(parent_scope) if is_funcdef: func = FunctionContext.from_context(parent_context, scope_node) if parent_context.is_class(): instance = AnonymousInstance( self, parent_context.parent_context, parent_context) func = BoundMethod( instance=instance, function=func ) if is_nested and not node_is_object: return func.get_function_execution() return func elif scope_node.type == 'classdef': return ClassContext(self, parent_context, scope_node) elif scope_node.type == 'comp_for': if node.start_pos >= scope_node.children[-1].start_pos: return parent_context return CompForContext.from_comp_for(parent_context, scope_node) raise Exception("There's a scope that was not managed.") base_node = base_context.tree_node if node_is_context and parser_utils.is_scope(node): scope_node = node else: scope_node = parent_scope(node) if scope_node.type in ('funcdef', 'classdef'): colon = scope_node.children[scope_node.children.index(':')] if node.start_pos < colon.start_pos: parent = node.parent if not (parent.type == 'param' and parent.name == node): scope_node = parent_scope(scope_node) return from_scope_node(scope_node, is_nested=True, node_is_object=node_is_object)
def parent_scope(node): while True: node = node.parent if parser_utils.is_scope(node): return node elif node.type in ('argument', 'testlist_comp'): if node.children[1].type == 'comp_for': return node.children[1] elif node.type == 'dictorsetmaker': for n in node.children[1:4]: # In dictionaries it can be pretty much anything. if n.type == 'comp_for': return n
def parent_scope(node): while True: node = node.parent if parser_utils.is_scope(node): return node elif node.type in ('argument', 'testlist_comp'): if node.children[1].type == 'comp_for': return node.children[1] elif node.type == 'dictorsetmaker': for n in node.children[1:4]: # In dictionaries it can be pretty much anything. if n.type == 'comp_for': return n
def filter_name(self, filters): """ Searches names that are defined in a scope (the different ``filters``), until a name fits. """ names = [] # This paragraph is currently needed for proper branch evaluation # (static analysis). if self._context.predefined_names and isinstance( self._name, tree.Name): node = self._name while node is not None and not is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for", 'sync_comp_for'): try: name_dict = self._context.predefined_names[node] types = name_dict[self._string_name] except KeyError: continue else: self._found_predefined_types = types break for filter in filters: names = filter.get(self._string_name) if names: if len(names) == 1: n, = names if isinstance(n, TreeNameDefinition): # Something somewhere went terribly wrong. This # typically happens when using goto on an import in an # __init__ file. I think we need a better solution, but # it's kind of hard, because for Jedi it's not clear # that that name has not been defined, yet. if n.tree_name == self._name: def_ = self._name.get_definition() if def_ is not None and def_.type == 'import_from': continue break debug.dbg('finder.filter_name %s in (%s): %s@%s', self._string_name, self._context, names, self._position) return list(names)
def filter_name(self, filters): """ Searches names that are defined in a scope (the different ``filters``), until a name fits. """ names = [] if self._context.predefined_names: # TODO is this ok? node might not always be a tree.Name node = self._name while node is not None and not is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for"): try: name_dict = self._context.predefined_names[node] types = name_dict[self._string_name] except KeyError: continue else: self._found_predefined_types = types break for filter in filters: names = filter.get(self._string_name) if names: if len(names) == 1: n, = names if isinstance(n, TreeNameDefinition): # Something somewhere went terribly wrong. This # typically happens when using goto on an import in an # __init__ file. I think we need a better solution, but # it's kind of hard, because for Jedi it's not clear # that that name has not been defined, yet. if n.tree_name == self._name: if self._name.get_definition().type == 'import_from': continue break debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name, self._context, names, self._position) return list(names)
def _check_flow_information(context, flow, search_name, pos): """ Try to find out the type of a variable just with the information that is given by the flows: e.g. It is also responsible for assert checks.:: if isinstance(k, str): k. # <- completion here ensures that `k` is a string. """ if not settings.dynamic_flow_information: return None result = None if is_scope(flow): # Check for asserts. module_node = flow.get_root_node() try: names = module_node.get_used_names()[search_name.value] except KeyError: return None names = reversed([ n for n in names if flow.start_pos <= n.start_pos < (pos or flow.end_pos) ]) for name in names: ass = search_ancestor(name, 'assert_stmt') if ass is not None: result = _check_isinstance_type(context, ass.assertion, search_name) if result is not None: return result if flow.type in ('if_stmt', 'while_stmt'): potential_ifs = [c for c in flow.children[1::4] if c != ':'] for if_test in reversed(potential_ifs): if search_name.start_pos > if_test.end_pos: return _check_isinstance_type(context, if_test, search_name) return result
def _check_flow_information(context, flow, search_name, pos): """ Try to find out the type of a variable just with the information that is given by the flows: e.g. It is also responsible for assert checks.:: if isinstance(k, str): k. # <- completion here ensures that `k` is a string. """ if not settings.dynamic_flow_information: return None result = None if is_scope(flow): # Check for asserts. module_node = flow.get_root_node() try: names = module_node.get_used_names()[search_name.value] except KeyError: return None names = reversed([ n for n in names if flow.start_pos <= n.start_pos < (pos or flow.end_pos) ]) for name in names: ass = search_ancestor(name, 'assert_stmt') if ass is not None: result = _check_isinstance_type(context, ass.assertion, search_name) if result is not None: return result if flow.type in ('if_stmt', 'while_stmt'): potential_ifs = [c for c in flow.children[1::4] if c != ':'] for if_test in reversed(potential_ifs): if search_name.start_pos > if_test.end_pos: return _check_isinstance_type(context, if_test, search_name) return result
def get_positions(self): import parso from jedi import parser_utils from parso.python import tree locs = [] def process_scope(scope): if isinstance(scope, tree.Function): # process all children after name node, # (otherwise name of global function will be marked as local def) local_names = set() global_names = set() for child in scope.children[2:]: process_node(child, local_names, global_names) else: if hasattr(scope, "subscopes"): for child in scope.subscopes: process_scope(child) elif hasattr(scope, "children"): for child in scope.children: process_scope(child) def process_node(node, local_names, global_names): if isinstance(node, tree.GlobalStmt): global_names.update([n.value for n in node.get_global_names()]) elif isinstance(node, tree.Name): if node.value in global_names: return if node.is_definition(): # local def locs.append(node) local_names.add(node.value) elif node.value in local_names: # use of local locs.append(node) elif isinstance(node, tree.BaseNode): # ref: jedi/parser/grammar*.txt if node.type == "trailer" and node.children[0].value == ".": # this is attribute return if isinstance(node, tree.Function): global_names = set( ) # outer global statement doesn't have effect anymore for child in node.children: process_node(child, local_names, global_names) source = self.text.get("1.0", "end") module = parso.parse(source) for child in module.children: if isinstance(child, tree.BaseNode) and parser_utils.is_scope(child): process_scope(child) loc_pos = set(( "%d.%d" % (usage.start_pos[0], usage.start_pos[1]), "%d.%d" % (usage.start_pos[0], usage.start_pos[1] + len(usage.value)), ) for usage in locs) return loc_pos
def infer_node(context, element): if isinstance(context, CompForContext): return _infer_node(context, element) if_stmt = element while if_stmt is not None: if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) # TODO there's a lot of issues with this one. We actually should do # this in a different way. Caching should only be active in certain # cases and this all sucks. if predefined_if_name_dict is None and if_stmt \ and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis: if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # value.predefined_names 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 = get_names_of_node(if_stmt_test) element_names = get_names_of_node(element) str_element_names = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: definitions = context.inference_state.infer( context, 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 inference %s.', if_stmt) # There's only a certain amount of branches # Jedi can infer, 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][if_name.value] = ValueSet( [definition]) name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[if_name.value] = definitions if len(name_dicts) > 1: result = NO_VALUES for name_dict in name_dicts: with context.predefine_names(if_stmt, name_dict): result |= _infer_node(context, element) return result else: return _infer_node_if_inferred(context, element) else: if predefined_if_name_dict: return _infer_node(context, element) else: return _infer_node_if_inferred(context, element)
def eval_element(self, context, element): if isinstance(context, iterable.CompForContext): return self._eval_element_not_cached(context, element) if_stmt = element while if_stmt is not None: if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) if predefined_if_name_dict is None and if_stmt and if_stmt.type == 'if_stmt': if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # context.predefined_names 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 = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(context, 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][if_name.value] = set([definition]) name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[if_name.value] = definitions if len(name_dicts) > 1: result = set() for name_dict in name_dicts: with helpers.predefine_names(context, if_stmt, name_dict): result |= self._eval_element_not_cached(context, element) return result else: return self._eval_element_if_evaluated(context, element) else: if predefined_if_name_dict: return self._eval_element_not_cached(context, element) else: return self._eval_element_if_evaluated(context, element)
def _get_flow_scopes(node): while True: node = get_parent_scope(node, include_flows=True) if node is None or is_scope(node): return yield node
def _get_flow_scopes(node): while True: node = get_parent_scope(node, include_flows=True) if node is None or is_scope(node): return yield node
def create_context(self, base_context, node, node_is_context=False, node_is_object=False): def parent_scope(node): while True: node = node.parent if parser_utils.is_scope(node): return node elif node.type in ('argument', 'testlist_comp'): if node.children[1].type == 'comp_for': return node.children[1] elif node.type == 'dictorsetmaker': for n in node.children[1:4]: # In dictionaries it can be pretty much anything. if n.type == 'comp_for': return n def from_scope_node(scope_node, child_is_funcdef=None, is_nested=True, node_is_object=False): if scope_node == base_node: return base_context is_funcdef = scope_node.type in ('funcdef', 'lambdef') parent_scope = parser_utils.get_parent_scope(scope_node) parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef) if is_funcdef: if isinstance(parent_context, AnonymousInstance): func = BoundMethod( self, parent_context, parent_context.class_context, parent_context.parent_context, scope_node ) else: func = FunctionContext( self, parent_context, scope_node ) if is_nested and not node_is_object: return func.get_function_execution() return func elif scope_node.type == 'classdef': class_context = ClassContext(self, parent_context, scope_node) if child_is_funcdef: # anonymous instance return AnonymousInstance(self, parent_context, class_context) else: return class_context elif scope_node.type == 'comp_for': if node.start_pos >= scope_node.children[-1].start_pos: return parent_context return CompForContext.from_comp_for(parent_context, scope_node) raise Exception("There's a scope that was not managed.") base_node = base_context.tree_node if node_is_context and parser_utils.is_scope(node): scope_node = node else: if node.parent.type in ('funcdef', 'classdef') and node.parent.name == node: # When we're on class/function names/leafs that define the # object itself and not its contents. node = node.parent scope_node = parent_scope(node) return from_scope_node(scope_node, is_nested=True, node_is_object=node_is_object)
def eval_element(self, context, element): if isinstance(context, CompForContext): return eval_node(context, element) if_stmt = element while if_stmt is not None: if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) # TODO there's a lot of issues with this one. We actually should do # this in a different way. Caching should only be active in certain # cases and this all sucks. if predefined_if_name_dict is None and if_stmt \ and if_stmt.type == 'if_stmt' and self.is_analysis: if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # context.predefined_names 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 = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(context, 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][if_name.value] = ContextSet(definition) name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[if_name.value] = definitions if len(name_dicts) > 1: result = ContextSet() for name_dict in name_dicts: with helpers.predefine_names(context, if_stmt, name_dict): result |= eval_node(context, element) return result else: return self._eval_element_if_evaluated(context, element) else: if predefined_if_name_dict: return eval_node(context, element) else: return self._eval_element_if_evaluated(context, element)