def _analysis(self): self._inference_state.is_analysis = True self._inference_state.analysis_modules = [self._module_node] module = self._get_module_context() 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_values(self._inference_state, 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.infer_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._inference_state.infer(context, node) else: defs = infer_call_of_leaf(context, node) try_iter_content(defs) self._inference_state.reset_recursion_limitations() ana = [a for a in self._inference_state.analysis if self.path == a.path] return sorted(set(ana), key=lambda x: x.line) finally: self._inference_state.is_analysis = False
def infer(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 = ClassValue(self, context, name.parent) else: c = FunctionValue.from_context(context, name.parent) return ValueSet([c]) if type_ == 'expr_stmt': is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return infer_expr_stmt(context, def_, name) if type_ == 'for_stmt': container_types = context.infer_node(def_.children[3]) cn = ContextualizedNode(context, def_.children[3]) for_types = iterate_values(container_types, cn) n = TreeNameDefinition(context, name) return check_tuple_assignments(n, for_types) if type_ in ('import_from', 'import_name'): return imports.infer_import(context, name) if type_ == 'with_stmt': return tree_name_to_values(self, context, name) elif type_ == 'param': return context.py__getattribute__(name.value, position=name.end_pos) else: result = follow_error_node_imports_if_possible(context, name) if result is not None: return result return helpers.infer_call_of_leaf(context, name)
def tree_name_to_values(inference_state, context, tree_name): value_set = NO_VALUES module_node = context.get_root_context().tree_node # First check for annotations, like: `foo: int = 3` if module_node is not None: names = module_node.get_used_names().get(tree_name.value, []) found_annotation = False for name in names: expr_stmt = name.parent if expr_stmt.type == "expr_stmt" and expr_stmt.children[ 1].type == "annassign": correct_scope = parser_utils.get_parent_scope( name) == context.tree_node if correct_scope: found_annotation = True value_set |= annotation.infer_annotation( context, expr_stmt.children[1].children[1]).execute_annotation( ) if found_annotation: return value_set types = [] node = tree_name.get_definition(import_name_always=True, include_setitem=True) if node is None: node = tree_name.parent if node.type == 'global_stmt': c = context.create_context(tree_name) if c.is_module(): # In case we are already part of the module, there is no point # in looking up the global statement anymore, because it's not # valid at that point anyway. return NO_VALUES # For global_stmt lookups, we only need the first possible scope, # which means the function itself. filter = next(c.get_filters()) names = filter.get(tree_name.value) return ValueSet.from_sets(name.infer() for name in names) elif node.type not in ('import_from', 'import_name'): c = context.create_context(tree_name) return infer_atom(c, tree_name) typ = node.type if typ == 'for_stmt': types = annotation.find_type_from_comment_hint_for( context, node, tree_name) if types: return types if typ == 'with_stmt': types = annotation.find_type_from_comment_hint_with( context, node, tree_name) if types: return types if typ in ('for_stmt', 'comp_for', 'sync_comp_for'): try: types = context.predefined_names[node][tree_name.value] except KeyError: cn = ContextualizedNode(context, node.children[3]) for_types = iterate_values( cn.infer(), contextualized_node=cn, is_async=node.parent.type == 'async_stmt', ) n = TreeNameDefinition(context, tree_name) types = check_tuple_assignments(n, for_types) elif typ == 'expr_stmt': types = infer_expr_stmt(context, node, tree_name) elif typ == 'with_stmt': value_managers = context.infer_node( node.get_test_node_from_name(tree_name)) if node.parent.type == 'async_stmt': # In the case of `async with` statements, we need to # first get the coroutine from the `__aenter__` method, # then "unwrap" via the `__await__` method enter_methods = value_managers.py__getattribute__('__aenter__') coro = enter_methods.execute_with_values() return coro.py__await__().py__stop_iteration_returns() enter_methods = value_managers.py__getattribute__('__enter__') return enter_methods.execute_with_values() elif typ in ('import_from', 'import_name'): types = imports.infer_import(context, tree_name) elif typ in ('funcdef', 'classdef'): types = _apply_decorators(context, node) elif typ == 'try_stmt': # TODO an exception can also be a tuple. Check for those. # TODO check for types that are not classes and add it to # the static analysis report. exceptions = context.infer_node( tree_name.get_previous_sibling().get_previous_sibling()) types = exceptions.execute_with_values() elif typ == 'param': types = NO_VALUES elif typ == 'del_stmt': types = NO_VALUES elif typ == 'namedexpr_test': types = infer_node(context, node) else: raise ValueError("Should not happen. type: %s" % typ) return types