mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 14:54:47 +08:00
move usages to its own api module usages
This commit is contained in:
@@ -24,6 +24,7 @@ from jedi import cache
|
|||||||
from jedi.api import keywords
|
from jedi.api import keywords
|
||||||
from jedi.api import classes
|
from jedi.api import classes
|
||||||
from jedi.api import interpreter
|
from jedi.api import interpreter
|
||||||
|
from jedi.api import usages
|
||||||
from jedi.evaluate import Evaluator, filter_private_variable
|
from jedi.evaluate import Evaluator, filter_private_variable
|
||||||
from jedi.evaluate import representation as er
|
from jedi.evaluate import representation as er
|
||||||
from jedi.evaluate import compiled
|
from jedi.evaluate import compiled
|
||||||
@@ -451,21 +452,21 @@ class Script(object):
|
|||||||
if unicode(v.names[-1]) == search_name]
|
if unicode(v.names[-1]) == search_name]
|
||||||
if not isinstance(user_stmt, pr.Import):
|
if not isinstance(user_stmt, pr.Import):
|
||||||
# import case is looked at with add_import_name option
|
# import case is looked at with add_import_name option
|
||||||
definitions = usages_add_import_modules(self._evaluator, definitions, search_name)
|
definitions = usages.usages_add_import_modules(self._evaluator, definitions, search_name)
|
||||||
|
|
||||||
module = set([d.get_parent_until() for d in definitions])
|
module = set([d.get_parent_until() for d in definitions])
|
||||||
module.add(self._parser.module())
|
module.add(self._parser.module())
|
||||||
names = usages(self._evaluator, definitions, search_name, module)
|
names = usages.usages(self._evaluator, definitions, search_name, module)
|
||||||
|
|
||||||
for d in set(definitions):
|
for d in set(definitions):
|
||||||
if isinstance(d, pr.Module):
|
if isinstance(d, pr.Module):
|
||||||
names.append(classes.Usage(self._evaluator, d, d))
|
names.append(usages.Usage(self._evaluator, d, d))
|
||||||
elif isinstance(d, er.Instance):
|
elif isinstance(d, er.Instance):
|
||||||
# Instances can be ignored, because they are being created by
|
# Instances can be ignored, because they are being created by
|
||||||
# ``__getattr__``.
|
# ``__getattr__``.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
names.append(classes.Usage(self._evaluator, d.names[-1], d))
|
names.append(usages.Usage(self._evaluator, d.names[-1], d))
|
||||||
|
|
||||||
settings.dynamic_flow_information = temp
|
settings.dynamic_flow_information = temp
|
||||||
return self._sorted_defs(set(names))
|
return self._sorted_defs(set(names))
|
||||||
@@ -667,88 +668,3 @@ def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
|
|||||||
debug.enable_warning = warnings
|
debug.enable_warning = warnings
|
||||||
debug.enable_notice = notices
|
debug.enable_notice = notices
|
||||||
debug.enable_speed = speed
|
debug.enable_speed = speed
|
||||||
|
|
||||||
|
|
||||||
# TODO move to a better place.
|
|
||||||
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(call):
|
|
||||||
result = []
|
|
||||||
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 name == search_name:
|
|
||||||
follow.append(call_path[:i + 1])
|
|
||||||
|
|
||||||
for f in follow:
|
|
||||||
follow_res, search = evaluator.goto(call.parent, f)
|
|
||||||
# names can change (getattr stuff), therefore filter names that
|
|
||||||
# don't match `search_name`.
|
|
||||||
|
|
||||||
# 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):
|
|
||||||
scope = call.parent
|
|
||||||
result.append(classes.Usage(evaluator, search, scope))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
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 name_part == search_name:
|
|
||||||
imps.append((count, name_part))
|
|
||||||
|
|
||||||
for used_count, name_part in imps:
|
|
||||||
i = imports.ImportPath(evaluator, stmt, kill_count=count - used_count,
|
|
||||||
direct_resolve=True)
|
|
||||||
f = i.follow(is_goto=True)
|
|
||||||
if set(f) & set(definitions):
|
|
||||||
names.append(classes.Usage(evaluator, name_part, stmt))
|
|
||||||
else:
|
|
||||||
for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True):
|
|
||||||
names += check_call(call)
|
|
||||||
return names
|
|
||||||
|
|
||||||
|
|
||||||
def usages_add_import_modules(evaluator, definitions, search_name):
|
|
||||||
""" Adds the modules of the imports """
|
|
||||||
new = set()
|
|
||||||
for d in definitions:
|
|
||||||
if isinstance(d.parent, pr.Import):
|
|
||||||
s = imports.ImportPath(evaluator, d.parent, direct_resolve=True)
|
|
||||||
with common.ignored(IndexError):
|
|
||||||
new.add(s.follow(is_goto=True)[0])
|
|
||||||
return set(definitions) | new
|
|
||||||
|
|||||||
@@ -557,25 +557,6 @@ def defined_names(evaluator, scope):
|
|||||||
return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)]
|
return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)]
|
||||||
|
|
||||||
|
|
||||||
class Usage(BaseDefinition):
|
|
||||||
"""TODO: document this"""
|
|
||||||
def __init__(self, evaluator, name_part, scope):
|
|
||||||
super(Usage, self).__init__(evaluator, scope, name_part.start_pos)
|
|
||||||
self.text = unicode(name_part)
|
|
||||||
self.end_pos = name_part.end_pos
|
|
||||||
|
|
||||||
@property
|
|
||||||
def description(self):
|
|
||||||
return "%s@%s,%s" % (self.text, self.line, self.column)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self._start_pos == other._start_pos \
|
|
||||||
and self.module_path == other.module_path
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash((self._start_pos, self.module_path))
|
|
||||||
|
|
||||||
|
|
||||||
class CallDef(object):
|
class CallDef(object):
|
||||||
"""
|
"""
|
||||||
`CallDef` objects is the return value of `Script.function_definition`.
|
`CallDef` objects is the return value of `Script.function_definition`.
|
||||||
|
|||||||
109
jedi/api/usages.py
Normal file
109
jedi/api/usages.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
from jedi._compatibility import unicode
|
||||||
|
from jedi import common
|
||||||
|
from jedi.api import classes
|
||||||
|
from jedi.parser import representation as pr
|
||||||
|
from jedi.evaluate import imports
|
||||||
|
from jedi.evaluate import helpers
|
||||||
|
|
||||||
|
|
||||||
|
class Usage(classes.BaseDefinition):
|
||||||
|
"""TODO: document this"""
|
||||||
|
def __init__(self, evaluator, name_part, scope):
|
||||||
|
super(Usage, self).__init__(evaluator, scope, name_part.start_pos)
|
||||||
|
self.text = unicode(name_part)
|
||||||
|
self.end_pos = name_part.end_pos
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return "%s@%s,%s" % (self.text, self.line, self.column)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self._start_pos == other._start_pos \
|
||||||
|
and self.module_path == other.module_path
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self._start_pos, self.module_path))
|
||||||
|
|
||||||
|
|
||||||
|
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(call):
|
||||||
|
result = []
|
||||||
|
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 name == search_name:
|
||||||
|
follow.append(call_path[:i + 1])
|
||||||
|
|
||||||
|
for f in follow:
|
||||||
|
follow_res, search = evaluator.goto(call.parent, f)
|
||||||
|
# names can change (getattr stuff), therefore filter names that
|
||||||
|
# don't match `search_name`.
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
scope = call.parent
|
||||||
|
result.append(Usage(evaluator, search, scope))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
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 name_part == search_name:
|
||||||
|
imps.append((count, name_part))
|
||||||
|
|
||||||
|
for used_count, name_part in imps:
|
||||||
|
i = imports.ImportPath(evaluator, stmt, kill_count=count - used_count,
|
||||||
|
direct_resolve=True)
|
||||||
|
f = i.follow(is_goto=True)
|
||||||
|
if set(f) & set(definitions):
|
||||||
|
names.append(Usage(evaluator, name_part, stmt))
|
||||||
|
else:
|
||||||
|
for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True):
|
||||||
|
names += check_call(call)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def usages_add_import_modules(evaluator, definitions, search_name):
|
||||||
|
""" Adds the modules of the imports """
|
||||||
|
new = set()
|
||||||
|
for d in definitions:
|
||||||
|
if isinstance(d.parent, pr.Import):
|
||||||
|
s = imports.ImportPath(evaluator, d.parent, direct_resolve=True)
|
||||||
|
with common.ignored(IndexError):
|
||||||
|
new.add(s.follow(is_goto=True)[0])
|
||||||
|
return set(definitions) | new
|
||||||
Reference in New Issue
Block a user