Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

changeset 3544
431c842fd09a
parent 3456
96232974dcdb
child 3670
f0cb7579c0b4
child 3890
ca6201559906
equal deleted inserted replaced
3542:07cde1e38b06 3544:431c842fd09a
12 Also, it models the Bindings and Scopes. 12 Also, it models the Bindings and Scopes.
13 """ 13 """
14 import doctest 14 import doctest
15 import os 15 import os
16 import sys 16 import sys
17 try: 17
18 builtin_vars = dir(__import__('builtins')) 18 PY2 = sys.version_info < (3, 0)
19 PY2 = False 19 PY32 = sys.version_info < (3, 3) # Python 2.5 to 3.2
20 except ImportError: 20 PY33 = sys.version_info < (3, 4) # Python 2.5 to 3.3
21 builtin_vars = dir(__import__('__builtin__')) 21 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins'))
22 PY2 = True
23 22
24 try: 23 try:
25 import ast 24 import ast
26 iter_child_nodes = ast.iter_child_nodes
27 except ImportError: # Python 2.5 25 except ImportError: # Python 2.5
28 import _ast as ast 26 import _ast as ast
29 27
30 if 'decorator_list' not in ast.ClassDef._fields: 28 if 'decorator_list' not in ast.ClassDef._fields:
31 # Patch the missing attribute 'decorator_list' 29 # Patch the missing attribute 'decorator_list'
32 ast.ClassDef.decorator_list = () 30 ast.ClassDef.decorator_list = ()
33 ast.FunctionDef.decorator_list = property(lambda s: s.decorators) 31 ast.FunctionDef.decorator_list = property(lambda s: s.decorators)
34
35 def iter_child_nodes(node):
36 """
37 Yield all direct child nodes of *node*, that is, all fields that
38 are nodes and all items of fields that are lists of nodes.
39 """
40 for name in node._fields:
41 field = getattr(node, name, None)
42 if isinstance(field, ast.AST):
43 yield field
44 elif isinstance(field, list):
45 for item in field:
46 yield item
47 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
48 if hasattr(ast, 'Try'):
49 ast_TryExcept = ast.Try
50 ast_TryFinally = ()
51 else:
52 ast_TryExcept = ast.TryExcept
53 ast_TryFinally = ast.TryFinally
54 32
55 from . import messages 33 from . import messages
56 34
57 35
58 if PY2: 36 if PY2:
61 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__ 39 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__
62 else: 40 else:
63 def getNodeType(node_class): 41 def getNodeType(node_class):
64 return node_class.__name__.upper() 42 return node_class.__name__.upper()
65 43
44 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
45 if PY32:
46 def getAlternatives(n):
47 if isinstance(n, (ast.If, ast.TryFinally)):
48 return [n.body]
49 if isinstance(n, ast.TryExcept):
50 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
51 else:
52 def getAlternatives(n):
53 if isinstance(n, ast.If):
54 return [n.body]
55 if isinstance(n, ast.Try):
56 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
57
58
59 class _FieldsOrder(dict):
60 """Fix order of AST node fields."""
61
62 def _get_fields(self, node_class):
63 # handle iter before target, and generators before element
64 fields = node_class._fields
65 if 'iter' in fields:
66 key_first = 'iter'.find
67 elif 'generators' in fields:
68 key_first = 'generators'.find
69 else:
70 key_first = 'value'.find
71 return tuple(sorted(fields, key=key_first, reverse=True))
72
73 def __missing__(self, node_class):
74 self[node_class] = fields = self._get_fields(node_class)
75 return fields
76
77
78 def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()):
79 """
80 Yield all direct child nodes of *node*, that is, all fields that
81 are nodes and all items of fields that are lists of nodes.
82 """
83 for name in _fields_order[node.__class__]:
84 if name == omit:
85 continue
86 field = getattr(node, name, None)
87 if isinstance(field, ast.AST):
88 yield field
89 elif isinstance(field, list):
90 for item in field:
91 yield item
92
66 93
67 class Binding(object): 94 class Binding(object):
68 """ 95 """
69 Represents the binding of a value to a name. 96 Represents the binding of a value to a name.
70 97
88 return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__, 115 return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
89 self.name, 116 self.name,
90 self.source.lineno, 117 self.source.lineno,
91 id(self)) 118 id(self))
92 119
93 120 def redefines(self, other):
94 class Importation(Binding): 121 return isinstance(other, Definition) and self.name == other.name
122
123
124 class Definition(Binding):
125 """
126 A binding that defines a function or a class.
127 """
128
129
130 class Importation(Definition):
95 """ 131 """
96 A binding created by an import statement. 132 A binding created by an import statement.
97 133
98 @ivar fullName: The complete name given to the import statement, 134 @ivar fullName: The complete name given to the import statement,
99 possibly including multiple dotted components. 135 possibly including multiple dotted components.
100 @type fullName: C{str} 136 @type fullName: C{str}
101 """ 137 """
138
102 def __init__(self, name, source): 139 def __init__(self, name, source):
103 self.fullName = name 140 self.fullName = name
141 self.redefined = []
104 name = name.split('.')[0] 142 name = name.split('.')[0]
105 super(Importation, self).__init__(name, source) 143 super(Importation, self).__init__(name, source)
106 144
145 def redefines(self, other):
146 if isinstance(other, Importation):
147 return self.fullName == other.fullName
148 return isinstance(other, Definition) and self.name == other.name
149
107 150
108 class Argument(Binding): 151 class Argument(Binding):
109 """ 152 """
110 Represents binding a name as an argument. 153 Represents binding a name as an argument.
111 """
112
113
114 class Definition(Binding):
115 """
116 A binding that defines a function or a class.
117 """ 154 """
118 155
119 156
120 class Assignment(Binding): 157 class Assignment(Binding):
121 """ 158 """
147 __all__ = ["foo", "bar"] 184 __all__ = ["foo", "bar"]
148 185
149 Names which are imported and not otherwise used but appear in the value of 186 Names which are imported and not otherwise used but appear in the value of
150 C{__all__} will not have an unused import warning reported for them. 187 C{__all__} will not have an unused import warning reported for them.
151 """ 188 """
152 def names(self): 189
153 """ 190 def __init__(self, name, source, scope):
154 Return a list of the names referenced by this binding. 191 if '__all__' in scope and isinstance(source, ast.AugAssign):
155 """ 192 self.names = list(scope['__all__'].names)
156 names = [] 193 else:
157 if isinstance(self.source, ast.List): 194 self.names = []
158 for node in self.source.elts: 195 if isinstance(source.value, (ast.List, ast.Tuple)):
196 for node in source.value.elts:
159 if isinstance(node, ast.Str): 197 if isinstance(node, ast.Str):
160 names.append(node.s) 198 self.names.append(node.s)
161 return names 199 super(ExportBinding, self).__init__(name, source)
162 200
163 201
164 class Scope(dict): 202 class Scope(dict):
165 importStarred = False # set to True when import * is found 203 importStarred = False # set to True when import * is found
166 204
185 223
186 def __init__(self): 224 def __init__(self):
187 super(FunctionScope, self).__init__() 225 super(FunctionScope, self).__init__()
188 # Simplify: manage the special locals as globals 226 # Simplify: manage the special locals as globals
189 self.globals = self.alwaysUsed.copy() 227 self.globals = self.alwaysUsed.copy()
228 self.returnValue = None # First non-empty return
229 self.isGenerator = False # Detect a generator
190 230
191 def unusedAssignments(self): 231 def unusedAssignments(self):
192 """ 232 """
193 Return a generator for the assignments which have not been used. 233 Return a generator for the assignments which have not been used.
194 """ 234 """
234 """ 274 """
235 275
236 nodeDepth = 0 276 nodeDepth = 0
237 offset = None 277 offset = None
238 traceTree = False 278 traceTree = False
239 withDoctest = ('PYFLAKES_NODOCTEST' not in os.environ)
240 279
241 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS) 280 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
242 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS') 281 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
243 if _customBuiltIns: 282 if _customBuiltIns:
244 builtIns.update(_customBuiltIns.split(',')) 283 builtIns.update(_customBuiltIns.split(','))
245 del _customBuiltIns 284 del _customBuiltIns
246 285
247 def __init__(self, tree, filename='(none)', builtins=None): 286 def __init__(self, tree, filename='(none)', builtins=None,
287 withDoctest='PYFLAKES_DOCTEST' in os.environ):
248 self._nodeHandlers = {} 288 self._nodeHandlers = {}
249 self._deferredFunctions = [] 289 self._deferredFunctions = []
250 self._deferredAssignments = [] 290 self._deferredAssignments = []
251 self.deadScopes = [] 291 self.deadScopes = []
252 self.messages = [] 292 self.messages = []
253 self.filename = filename 293 self.filename = filename
254 if builtins: 294 if builtins:
255 self.builtIns = self.builtIns.union(builtins) 295 self.builtIns = self.builtIns.union(builtins)
296 self.withDoctest = withDoctest
256 self.scopeStack = [ModuleScope()] 297 self.scopeStack = [ModuleScope()]
257 self.exceptHandlers = [()] 298 self.exceptHandlers = [()]
258 self.futuresAllowed = True 299 self.futuresAllowed = True
259 self.root = tree 300 self.root = tree
260 self.handleChildren(tree) 301 self.handleChildren(tree)
308 """ 349 """
309 Look at scopes which have been fully examined and report names in them 350 Look at scopes which have been fully examined and report names in them
310 which were imported but unused. 351 which were imported but unused.
311 """ 352 """
312 for scope in self.deadScopes: 353 for scope in self.deadScopes:
313 export = isinstance(scope.get('__all__'), ExportBinding) 354 if isinstance(scope.get('__all__'), ExportBinding):
314 if export: 355 all_names = set(scope['__all__'].names)
315 all = scope['__all__'].names()
316 if not scope.importStarred and \ 356 if not scope.importStarred and \
317 os.path.basename(self.filename) != '__init__.py': 357 os.path.basename(self.filename) != '__init__.py':
318 # Look for possible mistakes in the export list 358 # Look for possible mistakes in the export list
319 undefined = set(all) - set(scope) 359 undefined = all_names.difference(scope)
320 for name in undefined: 360 for name in undefined:
321 self.report(messages.UndefinedExport, 361 self.report(messages.UndefinedExport,
322 scope['__all__'].source, name) 362 scope['__all__'].source, name)
323 else: 363 else:
324 all = [] 364 all_names = []
325 365
326 # Look for imported names that aren't used. 366 # Look for imported names that aren't used.
327 for importation in scope.values(): 367 for value in scope.values():
328 if isinstance(importation, Importation): 368 if isinstance(value, Importation):
329 if not importation.used and importation.name not in all: 369 used = value.used or value.name in all_names
330 self.report(messages.UnusedImport, 370 if not used:
331 importation.source, importation.name) 371 messg = messages.UnusedImport
372 self.report(messg, value.source, value.name)
373 for node in value.redefined:
374 if isinstance(self.getParent(node), ast.For):
375 messg = messages.ImportShadowedByLoopVar
376 elif used:
377 continue
378 else:
379 messg = messages.RedefinedWhileUnused
380 self.report(messg, node, value.name, value.source)
332 381
333 def pushScope(self, scopeClass=FunctionScope): 382 def pushScope(self, scopeClass=FunctionScope):
334 self.scopeStack.append(scopeClass()) 383 self.scopeStack.append(scopeClass())
335 384
336 def pushFunctionScope(self): # XXX Deprecated
337 self.pushScope(FunctionScope)
338
339 def pushClassScope(self): # XXX Deprecated
340 self.pushScope(ClassScope)
341
342 def report(self, messageClass, *args, **kwargs): 385 def report(self, messageClass, *args, **kwargs):
343 self.messages.append(messageClass(self.filename, *args, **kwargs)) 386 self.messages.append(messageClass(self.filename, *args, **kwargs))
344 387
345 def hasParent(self, node, kind): 388 def getParent(self, node):
346 while hasattr(node, 'parent'): 389 # Lookup the first parent which is not Tuple, List or Starred
390 while True:
347 node = node.parent 391 node = node.parent
348 if isinstance(node, kind): 392 if not hasattr(node, 'elts') and not hasattr(node, 'ctx'):
349 return True 393 return node
350 394
351 def getCommonAncestor(self, lnode, rnode, stop=None): 395 def getCommonAncestor(self, lnode, rnode, stop):
352 if not stop: 396 if stop in (lnode, rnode) or not (hasattr(lnode, 'parent') and
353 stop = self.root 397 hasattr(rnode, 'parent')):
398 return None
354 if lnode is rnode: 399 if lnode is rnode:
355 return lnode 400 return lnode
356 if stop in (lnode, rnode): 401
357 return stop 402 if (lnode.depth > rnode.depth):
358
359 if not hasattr(lnode, 'parent') or not hasattr(rnode, 'parent'):
360 return
361 if (lnode.level > rnode.level):
362 return self.getCommonAncestor(lnode.parent, rnode, stop) 403 return self.getCommonAncestor(lnode.parent, rnode, stop)
363 if (rnode.level > lnode.level): 404 if (lnode.depth < rnode.depth):
364 return self.getCommonAncestor(lnode, rnode.parent, stop) 405 return self.getCommonAncestor(lnode, rnode.parent, stop)
365 return self.getCommonAncestor(lnode.parent, rnode.parent, stop) 406 return self.getCommonAncestor(lnode.parent, rnode.parent, stop)
366 407
367 def descendantOf(self, node, ancestors, stop=None): 408 def descendantOf(self, node, ancestors, stop):
368 for a in ancestors: 409 for a in ancestors:
369 if self.getCommonAncestor(node, a, stop) not in (stop, None): 410 if self.getCommonAncestor(node, a, stop):
370 return True 411 return True
371 return False 412 return False
372 413
373 def onFork(self, parent, lnode, rnode, items):
374 return (self.descendantOf(lnode, items, parent) ^
375 self.descendantOf(rnode, items, parent))
376
377 def differentForks(self, lnode, rnode): 414 def differentForks(self, lnode, rnode):
378 """True, if lnode and rnode are located on different forks of IF/TRY""" 415 """True, if lnode and rnode are located on different forks of IF/TRY"""
379 ancestor = self.getCommonAncestor(lnode, rnode) 416 ancestor = self.getCommonAncestor(lnode, rnode, self.root)
380 if isinstance(ancestor, ast.If): 417 parts = getAlternatives(ancestor)
381 for fork in (ancestor.body, ancestor.orelse): 418 if parts:
382 if self.onFork(ancestor, lnode, rnode, fork): 419 for items in parts:
420 if self.descendantOf(lnode, items, ancestor) ^ \
421 self.descendantOf(rnode, items, ancestor):
383 return True 422 return True
384 elif isinstance(ancestor, ast_TryExcept):
385 body = ancestor.body + ancestor.orelse
386 for fork in [body] + [[hdl] for hdl in ancestor.handlers]:
387 if self.onFork(ancestor, lnode, rnode, fork):
388 return True
389 elif isinstance(ancestor, ast_TryFinally):
390 if self.onFork(ancestor, lnode, rnode, ancestor.body):
391 return True
392 return False 423 return False
393 424
394 def addBinding(self, node, value, reportRedef=True): 425 def addBinding(self, node, value):
395 """ 426 """
396 Called when a binding is altered. 427 Called when a binding is altered.
397 428
398 - `node` is the statement responsible for the change 429 - `node` is the statement responsible for the change
399 - `value` is the optional new value, a Binding instance, associated 430 - `value` is the new value, a Binding instance
400 with the binding; if None, the binding is deleted if it exists. 431 """
401 - if `reportRedef` is True (default), rebinding while unused will be 432 # assert value.source in (node, node.parent):
402 reported. 433 for scope in self.scopeStack[::-1]:
403 """ 434 if value.name in scope:
404 redefinedWhileUnused = False 435 break
405 if not isinstance(self.scope, ClassScope): 436 existing = scope.get(value.name)
406 for scope in self.scopeStack[::-1]: 437
407 existing = scope.get(value.name) 438 if existing and not self.differentForks(node, existing.source):
408 if (isinstance(existing, Importation) 439
409 and not existing.used 440 parent_stmt = self.getParent(value.source)
410 and (not isinstance(value, Importation) or 441 if isinstance(existing, Importation) and isinstance(parent_stmt, ast.For):
411 value.fullName == existing.fullName) 442 self.report(messages.ImportShadowedByLoopVar,
412 and reportRedef 443 node, value.name, existing.source)
413 and not self.differentForks(node, existing.source)): 444
414 redefinedWhileUnused = True 445 elif scope is self.scope:
446 if (isinstance(parent_stmt, ast.comprehension) and
447 not isinstance(self.getParent(existing.source),
448 (ast.For, ast.comprehension))):
449 self.report(messages.RedefinedInListComp,
450 node, value.name, existing.source)
451 elif not existing.used and value.redefines(existing):
415 self.report(messages.RedefinedWhileUnused, 452 self.report(messages.RedefinedWhileUnused,
416 node, value.name, existing.source) 453 node, value.name, existing.source)
417 454
418 existing = self.scope.get(value.name) 455 elif isinstance(existing, Importation) and value.redefines(existing):
419 if not redefinedWhileUnused and self.hasParent(value.source, ast.ListComp): 456 existing.redefined.append(node)
420 if (existing and reportRedef 457
421 and not self.hasParent(existing.source, (ast.For, ast.ListComp)) 458 self.scope[value.name] = value
422 and not self.differentForks(node, existing.source)):
423 self.report(messages.RedefinedInListComp,
424 node, value.name, existing.source)
425
426 if (isinstance(existing, Definition)
427 and not existing.used
428 and not self.differentForks(node, existing.source)):
429 self.report(messages.RedefinedWhileUnused,
430 node, value.name, existing.source)
431 else:
432 self.scope[value.name] = value
433 459
434 def getNodeHandler(self, node_class): 460 def getNodeHandler(self, node_class):
435 try: 461 try:
436 return self._nodeHandlers[node_class] 462 return self._nodeHandlers[node_class]
437 except KeyError: 463 except KeyError:
496 # then it's probably a mistake 522 # then it's probably a mistake
497 self.report(messages.UndefinedLocal, 523 self.report(messages.UndefinedLocal,
498 scope[name].used[1], name, scope[name].source) 524 scope[name].used[1], name, scope[name].source)
499 break 525 break
500 526
501 parent = getattr(node, 'parent', None) 527 parent_stmt = self.getParent(node)
502 if isinstance(parent, (ast.For, ast.comprehension, ast.Tuple, ast.List)): 528 if isinstance(parent_stmt, (ast.For, ast.comprehension)) or (
529 parent_stmt != node.parent and
530 not self.isLiteralTupleUnpacking(parent_stmt)):
503 binding = Binding(name, node) 531 binding = Binding(name, node)
504 elif (parent is not None and name == '__all__' and 532 elif name == '__all__' and isinstance(self.scope, ModuleScope):
505 isinstance(self.scope, ModuleScope)): 533 binding = ExportBinding(name, node.parent, self.scope)
506 binding = ExportBinding(name, parent.value)
507 else: 534 else:
508 binding = Assignment(name, node) 535 binding = Assignment(name, node)
509 if name in self.scope: 536 if name in self.scope:
510 binding.used = self.scope[name].used 537 binding.used = self.scope[name].used
511 self.addBinding(node, binding) 538 self.addBinding(node, binding)
520 try: 547 try:
521 del self.scope[name] 548 del self.scope[name]
522 except KeyError: 549 except KeyError:
523 self.report(messages.UndefinedName, node, name) 550 self.report(messages.UndefinedName, node, name)
524 551
525 def handleChildren(self, tree): 552 def handleChildren(self, tree, omit=None):
526 for node in iter_child_nodes(tree): 553 for node in iter_child_nodes(tree, omit=omit):
527 self.handleNode(node, tree) 554 self.handleNode(node, tree)
555
556 def isLiteralTupleUnpacking(self, node):
557 if isinstance(node, ast.Assign):
558 for child in node.targets + [node.value]:
559 if not hasattr(child, 'elts'):
560 return False
561 return True
528 562
529 def isDocstring(self, node): 563 def isDocstring(self, node):
530 """ 564 """
531 Determine if the given node is a docstring, as long as it is at the 565 Determine if the given node is a docstring, as long as it is at the
532 correct place in the node tree. 566 correct place in the node tree.
553 print(' ' * self.nodeDepth + node.__class__.__name__) 587 print(' ' * self.nodeDepth + node.__class__.__name__)
554 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or 588 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or
555 self.isDocstring(node)): 589 self.isDocstring(node)):
556 self.futuresAllowed = False 590 self.futuresAllowed = False
557 self.nodeDepth += 1 591 self.nodeDepth += 1
558 node.level = self.nodeDepth 592 node.depth = self.nodeDepth
559 node.parent = parent 593 node.parent = parent
560 try: 594 try:
561 handler = self.getNodeHandler(node.__class__) 595 handler = self.getNodeHandler(node.__class__)
562 handler(node) 596 handler(node)
563 finally: 597 finally:
567 601
568 _getDoctestExamples = doctest.DocTestParser().get_examples 602 _getDoctestExamples = doctest.DocTestParser().get_examples
569 603
570 def handleDoctests(self, node): 604 def handleDoctests(self, node):
571 try: 605 try:
572 docstring, node_lineno = self.getDocstring(node.body[0]) 606 (docstring, node_lineno) = self.getDocstring(node.body[0])
573 if not docstring: 607 examples = docstring and self._getDoctestExamples(docstring)
574 return
575 examples = self._getDoctestExamples(docstring)
576 except (ValueError, IndexError): 608 except (ValueError, IndexError):
577 # e.g. line 6 of the docstring for <string> has inconsistent 609 # e.g. line 6 of the docstring for <string> has inconsistent
578 # leading whitespace: ... 610 # leading whitespace: ...
579 return 611 return
612 if not examples:
613 return
580 node_offset = self.offset or (0, 0) 614 node_offset = self.offset or (0, 0)
581 self.pushScope() 615 self.pushScope()
616 underscore_in_builtins = '_' in self.builtIns
617 if not underscore_in_builtins:
618 self.builtIns.add('_')
582 for example in examples: 619 for example in examples:
583 try: 620 try:
584 tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST) 621 tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST)
585 except SyntaxError: 622 except SyntaxError:
586 e = sys.exc_info()[1] 623 e = sys.exc_info()[1]
587 position = (node_lineno + example.lineno + e.lineno, 624 position = (node_lineno + example.lineno + e.lineno,
588 example.indent + 4 + e.offset) 625 example.indent + 4 + (e.offset or 0))
589 self.report(messages.DoctestSyntaxError, node, position) 626 self.report(messages.DoctestSyntaxError, node, position)
590 else: 627 else:
591 self.offset = (node_offset[0] + node_lineno + example.lineno, 628 self.offset = (node_offset[0] + node_lineno + example.lineno,
592 node_offset[1] + example.indent + 4) 629 node_offset[1] + example.indent + 4)
593 self.handleChildren(tree) 630 self.handleChildren(tree)
594 self.offset = node_offset 631 self.offset = node_offset
632 if not underscore_in_builtins:
633 self.builtIns.remove('_')
595 self.popScope() 634 self.popScope()
596 635
597 def ignore(self, node): 636 def ignore(self, node):
598 pass 637 pass
599 638
600 # "stmt" type nodes 639 # "stmt" type nodes
601 RETURN = DELETE = PRINT = WHILE = IF = WITH = WITHITEM = RAISE = \ 640 DELETE = PRINT = FOR = WHILE = IF = WITH = WITHITEM = RAISE = \
602 TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren 641 TRYFINALLY = ASSERT = EXEC = EXPR = ASSIGN = handleChildren
603 642
604 CONTINUE = BREAK = PASS = ignore 643 CONTINUE = BREAK = PASS = ignore
605 644
606 # "expr" type nodes 645 # "expr" type nodes
607 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = YIELDFROM = \ 646 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = \
608 COMPARE = CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = \ 647 COMPARE = CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = \
609 STARRED = handleChildren 648 STARRED = NAMECONSTANT = handleChildren
610 649
611 NUM = STR = BYTES = ELLIPSIS = ignore 650 NUM = STR = BYTES = ELLIPSIS = ignore
612 651
613 # "slice" type nodes 652 # "slice" type nodes
614 SLICE = EXTSLICE = INDEX = handleChildren 653 SLICE = EXTSLICE = INDEX = handleChildren
620 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \ 659 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
621 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \ 660 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
622 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore 661 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
623 662
624 # additional node types 663 # additional node types
625 COMPREHENSION = KEYWORD = handleChildren 664 LISTCOMP = COMPREHENSION = KEYWORD = handleChildren
626 665
627 def GLOBAL(self, node): 666 def GLOBAL(self, node):
628 """ 667 """
629 Keep track of globals declarations. 668 Keep track of globals declarations.
630 """ 669 """
631 if isinstance(self.scope, FunctionScope): 670 if isinstance(self.scope, FunctionScope):
632 self.scope.globals.update(node.names) 671 self.scope.globals.update(node.names)
633 672
634 NONLOCAL = GLOBAL 673 NONLOCAL = GLOBAL
635 674
636 def LISTCOMP(self, node):
637 # handle generators before element
638 for gen in node.generators:
639 self.handleNode(gen, node)
640 self.handleNode(node.elt, node)
641
642 def GENERATOREXP(self, node): 675 def GENERATOREXP(self, node):
643 self.pushScope(GeneratorScope) 676 self.pushScope(GeneratorScope)
644 # handle generators before element 677 self.handleChildren(node)
645 for gen in node.generators:
646 self.handleNode(gen, node)
647 self.handleNode(node.elt, node)
648 self.popScope() 678 self.popScope()
649 679
650 SETCOMP = GENERATOREXP 680 DICTCOMP = SETCOMP = GENERATOREXP
651
652 def DICTCOMP(self, node):
653 self.pushScope(GeneratorScope)
654 for gen in node.generators:
655 self.handleNode(gen, node)
656 self.handleNode(node.key, node)
657 self.handleNode(node.value, node)
658 self.popScope()
659
660 def FOR(self, node):
661 """
662 Process bindings for loop variables.
663 """
664 vars = []
665
666 def collectLoopVars(n):
667 if isinstance(n, ast.Name):
668 vars.append(n.id)
669 elif isinstance(n, ast.expr_context):
670 return
671 else:
672 for c in iter_child_nodes(n):
673 collectLoopVars(c)
674
675 collectLoopVars(node.target)
676 for varn in vars:
677 if (isinstance(self.scope.get(varn), Importation)
678 # unused ones will get an unused import warning
679 and self.scope[varn].used):
680 self.report(messages.ImportShadowedByLoopVar,
681 node, varn, self.scope[varn].source)
682
683 self.handleChildren(node)
684 681
685 def NAME(self, node): 682 def NAME(self, node):
686 """ 683 """
687 Handle occurrence of Name (which can be a load/store/delete access.) 684 Handle occurrence of Name (which can be a load/store/delete access.)
688 """ 685 """
700 else: 697 else:
701 # must be a Param context -- this only happens for names in function 698 # must be a Param context -- this only happens for names in function
702 # arguments, but these aren't dispatched through here 699 # arguments, but these aren't dispatched through here
703 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) 700 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
704 701
702 def RETURN(self, node):
703 if node.value and not self.scope.returnValue:
704 self.scope.returnValue = node.value
705 self.handleNode(node.value, node)
706
707 def YIELD(self, node):
708 self.scope.isGenerator = True
709 self.handleNode(node.value, node)
710
711 YIELDFROM = YIELD
712
705 def FUNCTIONDEF(self, node): 713 def FUNCTIONDEF(self, node):
706 for deco in node.decorator_list: 714 for deco in node.decorator_list:
707 self.handleNode(deco, node) 715 self.handleNode(deco, node)
716 self.LAMBDA(node)
708 self.addBinding(node, FunctionDefinition(node.name, node)) 717 self.addBinding(node, FunctionDefinition(node.name, node))
709 self.LAMBDA(node)
710 if self.withDoctest: 718 if self.withDoctest:
711 self.deferFunction(lambda: self.handleDoctests(node)) 719 self.deferFunction(lambda: self.handleDoctests(node))
712 720
713 def LAMBDA(self, node): 721 def LAMBDA(self, node):
714 args = [] 722 args = []
723 annotations = []
715 724
716 if PY2: 725 if PY2:
717 def addArgs(arglist): 726 def addArgs(arglist):
718 for arg in arglist: 727 for arg in arglist:
719 if isinstance(arg, ast.Tuple): 728 if isinstance(arg, ast.Tuple):
720 addArgs(arg.elts) 729 addArgs(arg.elts)
721 else: 730 else:
722 if arg.id in args:
723 self.report(messages.DuplicateArgument,
724 node, arg.id)
725 args.append(arg.id) 731 args.append(arg.id)
726 addArgs(node.args.args) 732 addArgs(node.args.args)
727 defaults = node.args.defaults 733 defaults = node.args.defaults
728 else: 734 else:
729 for arg in node.args.args + node.args.kwonlyargs: 735 for arg in node.args.args + node.args.kwonlyargs:
730 if arg.arg in args:
731 self.report(messages.DuplicateArgument,
732 node, arg.arg)
733 args.append(arg.arg) 736 args.append(arg.arg)
734 self.handleNode(arg.annotation, node) 737 annotations.append(arg.annotation)
735 if hasattr(node, 'returns'): # Only for FunctionDefs
736 for annotation in (node.args.varargannotation,
737 node.args.kwargannotation, node.returns):
738 self.handleNode(annotation, node)
739 defaults = node.args.defaults + node.args.kw_defaults 738 defaults = node.args.defaults + node.args.kw_defaults
740 739
741 # vararg/kwarg identifiers are not Name nodes 740 # Only for Python3 FunctionDefs
742 for wildcard in (node.args.vararg, node.args.kwarg): 741 is_py3_func = hasattr(node, 'returns')
742
743 for arg_name in ('vararg', 'kwarg'):
744 wildcard = getattr(node.args, arg_name)
743 if not wildcard: 745 if not wildcard:
744 continue 746 continue
745 if wildcard in args: 747 args.append(wildcard if PY33 else wildcard.arg)
746 self.report(messages.DuplicateArgument, node, wildcard) 748 if is_py3_func:
747 args.append(wildcard) 749 if PY33: # Python 2.5 to 3.3
748 for default in defaults: 750 argannotation = arg_name + 'annotation'
749 self.handleNode(default, node) 751 annotations.append(getattr(node.args, argannotation))
752 else: # Python >= 3.4
753 annotations.append(wildcard.annotation)
754
755 if is_py3_func:
756 annotations.append(node.returns)
757
758 if len(set(args)) < len(args):
759 for (idx, arg) in enumerate(args):
760 if arg in args[:idx]:
761 self.report(messages.DuplicateArgument, node, arg)
762
763 for child in annotations + defaults:
764 if child:
765 self.handleNode(child, node)
750 766
751 def runFunction(): 767 def runFunction():
752 768
753 self.pushScope() 769 self.pushScope()
754 for name in args: 770 for name in args:
755 self.addBinding(node, Argument(name, node), reportRedef=False) 771 self.addBinding(node, Argument(name, node))
756 if isinstance(node.body, list): 772 if isinstance(node.body, list):
757 # case for FunctionDefs 773 # case for FunctionDefs
758 for stmt in node.body: 774 for stmt in node.body:
759 self.handleNode(stmt, node) 775 self.handleNode(stmt, node)
760 else: 776 else:
766 Check to see if any assignments have not been used. 782 Check to see if any assignments have not been used.
767 """ 783 """
768 for name, binding in self.scope.unusedAssignments(): 784 for name, binding in self.scope.unusedAssignments():
769 self.report(messages.UnusedVariable, binding.source, name) 785 self.report(messages.UnusedVariable, binding.source, name)
770 self.deferAssignment(checkUnusedAssignments) 786 self.deferAssignment(checkUnusedAssignments)
787
788 if PY32:
789 def checkReturnWithArgumentInsideGenerator():
790 """
791 Check to see if there is any return statement with
792 arguments but the function is a generator.
793 """
794 if self.scope.isGenerator and self.scope.returnValue:
795 self.report(messages.ReturnWithArgsInsideGenerator,
796 self.scope.returnValue)
797 self.deferAssignment(checkReturnWithArgumentInsideGenerator)
771 self.popScope() 798 self.popScope()
772 799
773 self.deferFunction(runFunction) 800 self.deferFunction(runFunction)
774 801
775 def CLASSDEF(self, node): 802 def CLASSDEF(self, node):
790 self.deferFunction(lambda: self.handleDoctests(node)) 817 self.deferFunction(lambda: self.handleDoctests(node))
791 for stmt in node.body: 818 for stmt in node.body:
792 self.handleNode(stmt, node) 819 self.handleNode(stmt, node)
793 self.popScope() 820 self.popScope()
794 self.addBinding(node, ClassDefinition(node.name, node)) 821 self.addBinding(node, ClassDefinition(node.name, node))
795
796 def ASSIGN(self, node):
797 self.handleNode(node.value, node)
798 for target in node.targets:
799 self.handleNode(target, node)
800 822
801 def AUGASSIGN(self, node): 823 def AUGASSIGN(self, node):
802 self.handleNodeLoad(node.target) 824 self.handleNodeLoad(node.target)
803 self.handleNode(node.value, node) 825 self.handleNode(node.value, node)
804 self.handleNode(node.target, node) 826 self.handleNode(node.target, node)
841 self.exceptHandlers.append(handler_names) 863 self.exceptHandlers.append(handler_names)
842 for child in node.body: 864 for child in node.body:
843 self.handleNode(child, node) 865 self.handleNode(child, node)
844 self.exceptHandlers.pop() 866 self.exceptHandlers.pop()
845 # Process the other nodes: "except:", "else:", "finally:" 867 # Process the other nodes: "except:", "else:", "finally:"
846 for child in iter_child_nodes(node): 868 self.handleChildren(node, omit='body')
847 if child not in node.body:
848 self.handleNode(child, node)
849 869
850 TRYEXCEPT = TRY 870 TRYEXCEPT = TRY
851 871
852 def EXCEPTHANDLER(self, node): 872 def EXCEPTHANDLER(self, node):
853 # 3.x: in addition to handling children, we must handle the name of 873 # 3.x: in addition to handling children, we must handle the name of

eric ide

mercurial