def get_posibilities(evaluator, module, func_name): try: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if isinstance(stmt, pr.Import): continue calls = helpers.scan_statement_for_calls(stmt, func_name) for c in calls: # no execution means that params cannot be set call_path = list(c.generate_call_path()) pos = c.start_pos scope = stmt.parent # this whole stuff is just to not execute certain parts # (speed improvement), basically we could just call # ``eval_call_path`` on the call_path and it would # also work. def listRightIndex(lst, value): return len(lst) - lst[-1::-1].index(value) - 1 # Need to take right index, because there could be a # func usage before. call_path_simple = [ unicode(d) if isinstance(d, pr.NamePart) else d for d in call_path ] i = listRightIndex(call_path_simple, func_name) first, last = call_path[:i], call_path[i + 1:] if not last and not call_path_simple.index(func_name) != i: continue scopes = [scope] if first: scopes = evaluator.eval_call_path( iter(first), c.parent, pos) pos = None from jedi.evaluate import representation as er for scope in scopes: s = evaluator.find_types(scope, func_name, position=pos, search_global=not first, resolve_decorator=False) c = [ getattr(escope, 'base_func', None) or escope.base for escope in s if escope.isinstance(er.Function, er.Class) ] if compare in c: # only if we have the correct function we execute # it, otherwise just ignore it. evaluator.follow_path(iter(last), s, scope) return listener.param_possibilities
def get_posibilities(evaluator, module, func_name): try: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if isinstance(stmt, pr.Import): continue calls = helpers.scan_statement_for_calls(stmt, func_name) for c in calls: # no execution means that params cannot be set call_path = list(c.generate_call_path()) pos = c.start_pos scope = stmt.parent # this whole stuff is just to not execute certain parts # (speed improvement), basically we could just call # ``eval_call_path`` on the call_path and it would # also work. def listRightIndex(lst, value): return len(lst) - lst[-1::-1].index(value) - 1 # Need to take right index, because there could be a # func usage before. call_path_simple = [unicode(d) if isinstance(d, pr.NamePart) else d for d in call_path] i = listRightIndex(call_path_simple, func_name) first, last = call_path[:i], call_path[i + 1:] if not last and not call_path_simple.index(func_name) != i: continue scopes = [scope] if first: scopes = evaluator.eval_call_path(iter(first), scope, pos) pos = None from jedi.evaluate import representation as er for scope in scopes: s = evaluator.find_types(scope, func_name, position=pos, search_global=not first, resolve_decorator=False) c = [getattr(escope, 'base_func', None) or escope.base for escope in s if escope.isinstance(er.Function, er.Class)] if compare in c: # only if we have the correct function we execute # it, otherwise just ignore it. evaluator.follow_path(iter(last), s, scope) return listener.param_possibilities
def _check_array_additions(evaluator, compare_array, module, is_list): """ Checks if a `pr.Array` has "add" statements: >>> a = [""] >>> a.append(1) """ if not settings.dynamic_array_additions or isinstance( module, compiled.CompiledObject): return [] def check_calls(calls, add_name): """ Calls are processed here. The part before the call is searched and compared with the original Array. """ result = [] for c in calls: call_path = list(c.generate_call_path()) call_path_simple = [ unicode(n) if isinstance(n, pr.NamePart) else n for n in call_path ] separate_index = call_path_simple.index(add_name) if add_name == call_path_simple[-1] or separate_index == 0: # this means that there is no execution -> [].append # or the keyword is at the start -> append() continue backtrack_path = iter(call_path[:separate_index]) position = c.start_pos scope = c.get_parent_until(pr.IsScope) found = evaluator.eval_call_path(backtrack_path, scope, position) if not compare_array in found: continue params = call_path[separate_index + 1] if not params.values: continue # no params: just ignore it if add_name in ['append', 'add']: for param in params: result += evaluator.eval_statement(param) elif add_name in ['insert']: try: second_param = params[1] except IndexError: continue else: result += evaluator.eval_statement(second_param) elif add_name in ['extend', 'update']: for param in params: iterators = evaluator.eval_statement(param) result += get_iterator_types(iterators) return result from jedi.evaluate import representation as er def get_execution_parent(element, *stop_classes): """ Used to get an Instance/FunctionExecution parent """ if isinstance(element, Array): stmt = element._array.parent else: # is an Instance with an ArrayInstance inside stmt = element.var_args[0].var_args.parent if isinstance(stmt, er.InstanceElement): stop_classes = list(stop_classes) + [er.Function] return stmt.get_parent_until(stop_classes) temp_param_add = settings.dynamic_params_for_other_modules settings.dynamic_params_for_other_modules = False search_names = ['append', 'extend', 'insert'] if is_list else \ ['add', 'update'] comp_arr_parent = get_execution_parent(compare_array, er.FunctionExecution) possible_stmts = [] res = [] for n in search_names: try: possible_stmts += module.used_names[n] except KeyError: continue for stmt in possible_stmts: # Check if the original scope is an execution. If it is, one # can search for the same statement, that is in the module # dict. Executions are somewhat special in jedi, since they # literally copy the contents of a function. if isinstance(comp_arr_parent, er.FunctionExecution): stmt = comp_arr_parent. \ get_statement_for_position(stmt.start_pos) if stmt is None: continue # InstanceElements are special, because they don't get copied, # but have this wrapper around them. if isinstance(comp_arr_parent, er.InstanceElement): stmt = er.InstanceElement(comp_arr_parent.instance, stmt) if evaluator.recursion_detector.push_stmt(stmt): # check recursion continue res += check_calls(helpers.scan_statement_for_calls(stmt, n), n) evaluator.recursion_detector.pop_stmt() # reset settings settings.dynamic_params_for_other_modules = temp_param_add return res
def _check_array_additions(evaluator, compare_array, module, is_list): """ Checks if a `pr.Array` has "add" statements: >>> a = [""] >>> a.append(1) """ if not settings.dynamic_array_additions or isinstance(module, compiled.CompiledObject): return [] def check_calls(calls, add_name): """ Calls are processed here. The part before the call is searched and compared with the original Array. """ result = [] for c in calls: call_path = list(c.generate_call_path()) separate_index = call_path.index(add_name) if add_name == call_path[-1] or separate_index == 0: # this means that there is no execution -> [].append # or the keyword is at the start -> append() continue backtrack_path = iter(call_path[:separate_index]) position = c.start_pos scope = c.get_parent_until(pr.IsScope) found = evaluator.eval_call_path(backtrack_path, scope, position) if not compare_array in found: continue params = call_path[separate_index + 1] if not params.values: continue # no params: just ignore it if add_name in ['append', 'add']: for param in params: result += evaluator.eval_statement(param) elif add_name in ['insert']: try: second_param = params[1] except IndexError: continue else: result += evaluator.eval_statement(second_param) elif add_name in ['extend', 'update']: for param in params: iterators = evaluator.eval_statement(param) result += get_iterator_types(iterators) return result from jedi.evaluate import representation as er def get_execution_parent(element, *stop_classes): """ Used to get an Instance/FunctionExecution parent """ if isinstance(element, Array): stmt = element._array.parent else: # is an Instance with an ArrayInstance inside stmt = element.var_args[0].var_args.parent if isinstance(stmt, er.InstanceElement): stop_classes = list(stop_classes) + [er.Function] return stmt.get_parent_until(stop_classes) temp_param_add = settings.dynamic_params_for_other_modules settings.dynamic_params_for_other_modules = False search_names = ['append', 'extend', 'insert'] if is_list else \ ['add', 'update'] comp_arr_parent = get_execution_parent(compare_array, er.FunctionExecution) possible_stmts = [] res = [] for n in search_names: try: possible_stmts += module.used_names[n] except KeyError: continue for stmt in possible_stmts: # Check if the original scope is an execution. If it is, one # can search for the same statement, that is in the module # dict. Executions are somewhat special in jedi, since they # literally copy the contents of a function. if isinstance(comp_arr_parent, er.FunctionExecution): stmt = comp_arr_parent. \ get_statement_for_position(stmt.start_pos) if stmt is None: continue # InstanceElements are special, because they don't get copied, # but have this wrapper around them. if isinstance(comp_arr_parent, er.InstanceElement): stmt = er.InstanceElement(comp_arr_parent.instance, stmt) if evaluator.recursion_detector.push_stmt(stmt): # check recursion continue res += check_calls(helpers.scan_statement_for_calls(stmt, n), n) evaluator.recursion_detector.pop_stmt() # reset settings settings.dynamic_params_for_other_modules = temp_param_add return res
def usages(evaluator, definitions, search_name, mods): def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result def check_call_for_usage(call): stmt = call.parent while not isinstance(stmt.parent, pr.IsScope): stmt = stmt.parent # New definition, call cannot be a part of stmt if len(call.name) == 1 and call.execution is None \ and call.name in stmt.get_defined_names(): # Class params are not definitions (like function params). They # are super classes, that need to be resolved. if not (isinstance(stmt, pr.Param) and isinstance(stmt.parent, pr.Class)): return follow = [] # There might be multiple search_name's in one call_path call_path = list(call.generate_call_path()) for i, name in enumerate(call_path): # name is `pr.NamePart`. if u(name) == search_name: follow.append(call_path[:i + 1]) for call_path in follow: follow_res, search = evaluator.goto(call.parent, call_path) # names can change (getattr stuff), therefore filter names that # don't match `search`. # TODO add something like that in the future - for now usages are # completely broken anyway. #follow_res = [r for r in follow_res if str(r) == search] #print search.start_pos,search_name.start_pos #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res] follow_res = usages_add_import_modules(evaluator, follow_res, search) compare_follow_res = compare_array(follow_res) # compare to see if they match if any(r in compare_definitions for r in compare_follow_res): yield classes.Definition(evaluator, search) if not definitions: return set() compare_definitions = compare_array(definitions) mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in imports.get_modules_containing_name(mods, search_name): try: stmts = m.used_names[search_name] except KeyError: continue for stmt in stmts: if isinstance(stmt, pr.Import): count = 0 imps = [] for i in stmt.get_all_import_names(): for name_part in i.names: count += 1 if unicode(name_part) == search_name: imps.append((count, name_part)) for used_count, name_part in imps: i = imports.ImportWrapper(evaluator, stmt, kill_count=count - used_count, nested_resolve=True) f = i.follow(is_goto=True) if set(f) & set(definitions): names.append(classes.Definition(evaluator, name_part)) else: for call in helpers.scan_statement_for_calls( stmt, search_name, assignment_details=True): names += check_call_for_usage(call) return names
def usages(evaluator, definitions, search_name, mods): def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result def check_call_for_usage(call): stmt = call.parent while not isinstance(stmt.parent, pr.IsScope): stmt = stmt.parent # New definition, call cannot be a part of stmt if len(call.name) == 1 and call.execution is None \ and call.name in stmt.get_defined_names(): # Class params are not definitions (like function params). They # are super classes, that need to be resolved. if not (isinstance(stmt, pr.Param) and isinstance(stmt.parent, pr.Class)): return follow = [] # There might be multiple search_name's in one call_path call_path = list(call.generate_call_path()) for i, name in enumerate(call_path): # name is `pr.NamePart`. if u(name) == search_name: follow.append(call_path[:i + 1]) for call_path in follow: follow_res, search = evaluator.goto(call.parent, call_path) # names can change (getattr stuff), therefore filter names that # don't match `search`. # TODO add something like that in the future - for now usages are # completely broken anyway. #follow_res = [r for r in follow_res if str(r) == search] #print search.start_pos,search_name.start_pos #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res] follow_res = usages_add_import_modules(evaluator, follow_res, search) compare_follow_res = compare_array(follow_res) # compare to see if they match if any(r in compare_definitions for r in compare_follow_res): yield classes.Definition(evaluator, search) if not definitions: return set() compare_definitions = compare_array(definitions) mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in imports.get_modules_containing_name(mods, search_name): try: stmts = m.used_names[search_name] except KeyError: continue for stmt in stmts: if isinstance(stmt, pr.Import): count = 0 imps = [] for i in stmt.get_all_import_names(): for name_part in i.names: count += 1 if unicode(name_part) == search_name: imps.append((count, name_part)) for used_count, name_part in imps: i = imports.ImportWrapper(evaluator, stmt, kill_count=count - used_count, nested_resolve=True) f = i.follow(is_goto=True) if set(f) & set(definitions): names.append(classes.Definition(evaluator, name_part)) else: for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True): names += check_call_for_usage(call) return names