forked from VimPlug/jedi
Re-enable AttributeError/NameError detection for more complicated occurances than just statements.
This commit is contained in:
@@ -609,17 +609,33 @@ class Script(object):
|
||||
for o in origins if hasattr(o, 'py__call__')]
|
||||
|
||||
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()))
|
||||
stmts, imp_names = analysis.get_module_statements(self._parser.module())
|
||||
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:
|
||||
iw = imports.ImportWrapper(self._evaluator, n).follow()
|
||||
i = n.get_definition()
|
||||
if i.is_nested() and any(not isinstance(i, pr.Module) for i in iw):
|
||||
analysis.add(self._evaluator, 'import-error', i.namespace_names[-1])
|
||||
for stmt in sorted(stmts, key=lambda obj: obj.start_pos):
|
||||
for node in sorted(nodes, key=lambda obj: obj.start_pos):
|
||||
#if not (isinstance(stmt.parent, pr.ForFlow) and stmt.parent.set_stmt == stmt):
|
||||
self._evaluator.eval_statement(stmt)
|
||||
if node.type == 'expr_stmt':
|
||||
check_types(self._evaluator.eval_statement(node))
|
||||
else:
|
||||
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)
|
||||
|
||||
@@ -195,6 +195,28 @@ def get_module_statements(module):
|
||||
Returns the statements used in a module. All these statements should be
|
||||
evaluated to check for potential exceptions.
|
||||
"""
|
||||
def check_children(node):
|
||||
try:
|
||||
children = node.children
|
||||
except AttributeError:
|
||||
return []
|
||||
else:
|
||||
nodes = []
|
||||
for child in children:
|
||||
nodes += check_children(child)
|
||||
if child.type == 'trailer':
|
||||
c = child.children
|
||||
if c[0] == '(' and c[1] != ')':
|
||||
if c[1].type != 'arglist':
|
||||
nodes.append(c[1])
|
||||
else:
|
||||
for argument in c[1].children:
|
||||
if argument.type == 'argument':
|
||||
nodes.append(argument.children[-1])
|
||||
elif argument.type != 'operator':
|
||||
nodes.append(argument)
|
||||
return nodes
|
||||
|
||||
def add_stmts(stmts):
|
||||
new = set()
|
||||
for stmt in stmts:
|
||||
@@ -203,28 +225,36 @@ def get_module_statements(module):
|
||||
new |= add_stmts(stmt.inputs)
|
||||
stmt = stmt.next
|
||||
continue
|
||||
if isinstance(stmt, pr.KeywordStatement):
|
||||
|
||||
stmt = stmt.stmt
|
||||
if stmt is None:
|
||||
continue
|
||||
|
||||
if stmt.type == 'expr_stmt':
|
||||
new.add(stmt)
|
||||
|
||||
for node in stmt.children:
|
||||
new.update(check_children(node))
|
||||
if node.type != 'keyword' and stmt.type != 'expr_stmt':
|
||||
new.add(node)
|
||||
return new
|
||||
|
||||
stmts = set()
|
||||
nodes = set()
|
||||
import_names = set()
|
||||
decorated_funcs = []
|
||||
for scope in module.walk():
|
||||
for imp in set(scope.imports):
|
||||
import_names |= set(imp.get_defined_names())
|
||||
if imp.is_nested():
|
||||
import_names |= set(path[-1] for path in imp.paths())
|
||||
stmts |= add_stmts(scope.statements)
|
||||
stmts |= add_stmts(r for r in scope.returns if r is not None)
|
||||
nodes |= add_stmts(scope.statements)
|
||||
nodes |= add_stmts(r for r in scope.returns if r is not None)
|
||||
|
||||
try:
|
||||
decorators = scope.decorators
|
||||
decorators = scope.get_decorators()
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
stmts |= add_stmts(decorators)
|
||||
return stmts, import_names
|
||||
if decorators:
|
||||
decorated_funcs.append(scope)
|
||||
return nodes, import_names, decorated_funcs
|
||||
|
||||
@@ -159,7 +159,7 @@ class CompiledObject(Base):
|
||||
else:
|
||||
raise KeyError("CompiledObject doesn't have an attribute '%s'." % name)
|
||||
|
||||
def get_index_types(self, evaluator, index_array):
|
||||
def get_index_types(self, evaluator, index_array=()):
|
||||
# If the object doesn't have `__getitem__`, just raise the
|
||||
# AttributeError.
|
||||
if not hasattr(self.obj, '__getitem__'):
|
||||
|
||||
@@ -375,7 +375,7 @@ class FakeImport(pr.Import):
|
||||
def start_pos(self):
|
||||
return 0, 0
|
||||
|
||||
def _paths(self):
|
||||
def paths(self):
|
||||
return [[self.name]]
|
||||
|
||||
|
||||
|
||||
@@ -248,6 +248,9 @@ class Array(IterableWrapper):
|
||||
# Can raise an IndexError
|
||||
return self._evaluator.eval_element(self._items()[mixed_index])
|
||||
|
||||
def iter_content(self):
|
||||
return self.values()
|
||||
|
||||
def scope_names_generator(self, position=None):
|
||||
"""
|
||||
It returns e.g. for a list: append, pop, ...
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
def generator():
|
||||
yield 1
|
||||
|
||||
#! 11 type-error-generator
|
||||
#! 12 type-error-generator
|
||||
generator()[0]
|
||||
|
||||
list(generator())[0]
|
||||
|
||||
Reference in New Issue
Block a user