def _analysis(self): self._evaluator.is_analysis = True self._evaluator.analysis_modules = [self._get_module()] try: for node in self._get_module().nodes_to_execute(): if node.type in ('funcdef', 'classdef'): if node.type == 'classdef': continue raise NotImplementedError er.Function(self._evaluator, node).get_decorated_func() 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.paths()) for n in import_names: imports.ImportWrapper(self._evaluator, n).follow() elif node.type == 'expr_stmt': types = self._evaluator.eval_element(node) for testlist in node.children[:-1:2]: # Iterate tuples. unpack_tuple_to_dict(self._evaluator, types, testlist) else: try_iter_content(self._evaluator.goto_definitions(node)) 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 _eval_statement_element(self, element): if pr.Array.is_type(element, pr.Array.NOARRAY): r = list( itertools.chain.from_iterable( self.eval_statement(s) for s in element)) call_path = element.generate_call_path() next(call_path, None) # the first one has been used already return self.follow_path(call_path, r, element.parent) elif isinstance(element, pr.ListComprehension): loop = _evaluate_list_comprehension(element) # Caveat: parents are being changed, but this doesn't matter, # because nothing else uses it. element.stmt.parent = loop return self.eval_statement(element.stmt) elif isinstance(element, pr.Lambda): return [er.Function(self, element)] # With things like params, these can also be functions... elif isinstance(element, pr.Base) and element.isinstance( er.Function, er.Class, er.Instance, iterable.ArrayInstance): return [element] # The string tokens are just operations (+, -, etc.) elif isinstance(element, compiled.CompiledObject): return [element] elif not isinstance(element, Token): return self.eval_call(element) else: return []
def _analysis(self): def check_types(types): for typ in types: try: f = typ.iter_content except AttributeError: pass else: check_types(f()) #statements = set(chain(*self._parser.module().used_names.values())) nodes, imp_names, decorated_funcs = \ analysis.get_module_statements(self._parser.module()) # Sort the statements so that the results are reproducible. for n in imp_names: imports.ImportWrapper(self._evaluator, n).follow() for node in sorted(nodes, key=lambda obj: obj.start_pos): #if not (isinstance(stmt.parent, pr.ForFlow) and stmt.parent.set_stmt == stmt): if node.type == 'expr_stmt': check_types(self._evaluator.eval_statement(node)) else: check_types(self._evaluator.eval_element(node)) for dec_func in decorated_funcs: er.Function(self._evaluator, dec_func).get_decorated_func() ana = [a for a in self._evaluator.analysis if self.path == a.path] return sorted(set(ana), key=lambda x: x.line)
def eval_statement_element(self, element): if pr.Array.is_type(element, pr.Array.NOARRAY): try: lst_cmp = element[0].expression_list()[0] if not isinstance(lst_cmp, pr.ListComprehension): raise IndexError except IndexError: r = list( itertools.chain.from_iterable( self.eval_statement(s) for s in element)) else: r = [iterable.GeneratorComprehension(self, lst_cmp)] call_path = element.generate_call_path() next(call_path, None) # the first one has been used already return self.follow_path(call_path, r, element.parent) elif isinstance(element, pr.ListComprehension): return self.eval_statement(element.stmt) elif isinstance(element, pr.Lambda): return [er.Function(self, element)] # With things like params, these can also be functions... elif isinstance(element, pr.Base) and element.isinstance( er.Function, er.Class, er.Instance, iterable.ArrayInstance): return [element] # The string tokens are just operations (+, -, etc.) elif isinstance(element, compiled.CompiledObject): return [element] elif isinstance(element, Token): return [] else: return self.eval_call(element)
def _names_to_types(self, names, resolve_decorator): types = [] # Add isinstance and other if/assert knowledge. flow_scope = self.scope evaluator = self._evaluator while flow_scope: # TODO check if result is in scope -> no evaluation necessary n = check_flow_information(evaluator, flow_scope, self.name_str, self.position) if n: return n flow_scope = flow_scope.parent for name in names: typ = name.parent if typ.isinstance(pr.ForFlow): types += self._handle_for_loops(typ) elif isinstance(typ, pr.Param): types += self._eval_param(typ) elif typ.isinstance(pr.Statement): if typ.is_global(): # global keyword handling. types += evaluator.find_types(typ.parent.parent, str(name)) else: types += self._remove_statements(typ) else: if isinstance(typ, pr.Class): typ = er.Class(evaluator, typ) elif isinstance(typ, pr.Function): typ = er.Function(evaluator, typ) if typ.isinstance(er.Function) and resolve_decorator: typ = typ.get_decorated_func() types.append(typ) return types
def wrap(self, element): if isinstance(element, tree.Class): return er.Class(self, element) elif isinstance(element, tree.Function): if isinstance(element, tree.Lambda): return er.LambdaWrapper(self, element) else: return er.Function(self, element) elif isinstance(element, (tree.Module)) \ and not isinstance(element, er.ModuleWrapper): return er.ModuleWrapper(self, element) else: return element
def _follow_statements_imports(self): stripped = self._definition if isinstance(stripped, pr.Name): stripped = stripped.parent # We should probably work in `Finder._names_to_types` here. if isinstance(stripped, pr.Function): stripped = er.Function(self._evaluator, stripped) elif isinstance(stripped, pr.Class): stripped = er.Class(self._evaluator, stripped) if stripped.isinstance(pr.Statement): return self._evaluator.eval_statement(stripped) elif stripped.isinstance(pr.Import): return imports.strip_imports(self._evaluator, [stripped]) else: return [stripped]
def wrap(self, element): if isinstance(element, (er.Wrapper, er.InstanceElement, er.ModuleWrapper, er.FunctionExecution, er.Instance, compiled.CompiledObject)) or element is None: # TODO this is so ugly, please refactor. id:211 gh:212 return element if element.type == 'classdef': return er.Class(self, element) elif element.type == 'funcdef': return er.Function(self, element) elif element.type == 'lambda': return er.LambdaWrapper(self, element) elif element.type == 'file_input': return er.ModuleWrapper(self, element) else: return element