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__')]
|
for o in origins if hasattr(o, 'py__call__')]
|
||||||
|
|
||||||
def _analysis(self):
|
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()))
|
#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.
|
# Sort the statements so that the results are reproducible.
|
||||||
for n in imp_names:
|
for n in imp_names:
|
||||||
iw = imports.ImportWrapper(self._evaluator, n).follow()
|
iw = imports.ImportWrapper(self._evaluator, n).follow()
|
||||||
i = n.get_definition()
|
i = n.get_definition()
|
||||||
if i.is_nested() and any(not isinstance(i, pr.Module) for i in iw):
|
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])
|
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):
|
#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]
|
ana = [a for a in self._evaluator.analysis if self.path == a.path]
|
||||||
return sorted(set(ana), key=lambda x: x.line)
|
return sorted(set(ana), key=lambda x: x.line)
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ class Error(object):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s %s: %s@%s,%s>' % (self.__class__.__name__,
|
return '<%s %s: %s@%s,%s>' % (self.__class__.__name__,
|
||||||
self.name, self.path,
|
self.name, self.path,
|
||||||
self._start_pos[0], self._start_pos[1])
|
self._start_pos[0], self._start_pos[1])
|
||||||
|
|
||||||
|
|
||||||
class Warning(Error):
|
class Warning(Error):
|
||||||
@@ -195,6 +195,28 @@ def get_module_statements(module):
|
|||||||
Returns the statements used in a module. All these statements should be
|
Returns the statements used in a module. All these statements should be
|
||||||
evaluated to check for potential exceptions.
|
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):
|
def add_stmts(stmts):
|
||||||
new = set()
|
new = set()
|
||||||
for stmt in stmts:
|
for stmt in stmts:
|
||||||
@@ -203,28 +225,36 @@ def get_module_statements(module):
|
|||||||
new |= add_stmts(stmt.inputs)
|
new |= add_stmts(stmt.inputs)
|
||||||
stmt = stmt.next
|
stmt = stmt.next
|
||||||
continue
|
continue
|
||||||
if isinstance(stmt, pr.KeywordStatement):
|
|
||||||
stmt = stmt.stmt
|
stmt = stmt.stmt
|
||||||
if stmt is None:
|
if stmt is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
new.add(stmt)
|
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
|
return new
|
||||||
|
|
||||||
stmts = set()
|
nodes = set()
|
||||||
import_names = set()
|
import_names = set()
|
||||||
|
decorated_funcs = []
|
||||||
for scope in module.walk():
|
for scope in module.walk():
|
||||||
for imp in set(scope.imports):
|
for imp in set(scope.imports):
|
||||||
import_names |= set(imp.get_defined_names())
|
import_names |= set(imp.get_defined_names())
|
||||||
if imp.is_nested():
|
if imp.is_nested():
|
||||||
import_names |= set(path[-1] for path in imp.paths())
|
import_names |= set(path[-1] for path in imp.paths())
|
||||||
stmts |= add_stmts(scope.statements)
|
nodes |= add_stmts(scope.statements)
|
||||||
stmts |= add_stmts(r for r in scope.returns if r is not None)
|
nodes |= add_stmts(r for r in scope.returns if r is not None)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decorators = scope.decorators
|
decorators = scope.get_decorators()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
stmts |= add_stmts(decorators)
|
if decorators:
|
||||||
return stmts, import_names
|
decorated_funcs.append(scope)
|
||||||
|
return nodes, import_names, decorated_funcs
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class CompiledObject(Base):
|
|||||||
else:
|
else:
|
||||||
raise KeyError("CompiledObject doesn't have an attribute '%s'." % name)
|
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
|
# If the object doesn't have `__getitem__`, just raise the
|
||||||
# AttributeError.
|
# AttributeError.
|
||||||
if not hasattr(self.obj, '__getitem__'):
|
if not hasattr(self.obj, '__getitem__'):
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ class FakeImport(pr.Import):
|
|||||||
def start_pos(self):
|
def start_pos(self):
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
def _paths(self):
|
def paths(self):
|
||||||
return [[self.name]]
|
return [[self.name]]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -248,6 +248,9 @@ class Array(IterableWrapper):
|
|||||||
# Can raise an IndexError
|
# Can raise an IndexError
|
||||||
return self._evaluator.eval_element(self._items()[mixed_index])
|
return self._evaluator.eval_element(self._items()[mixed_index])
|
||||||
|
|
||||||
|
def iter_content(self):
|
||||||
|
return self.values()
|
||||||
|
|
||||||
def scope_names_generator(self, position=None):
|
def scope_names_generator(self, position=None):
|
||||||
"""
|
"""
|
||||||
It returns e.g. for a list: append, pop, ...
|
It returns e.g. for a list: append, pop, ...
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
def generator():
|
def generator():
|
||||||
yield 1
|
yield 1
|
||||||
|
|
||||||
#! 11 type-error-generator
|
#! 12 type-error-generator
|
||||||
generator()[0]
|
generator()[0]
|
||||||
|
|
||||||
list(generator())[0]
|
list(generator())[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user