Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

branch
BgService
changeset 3177
5af61402d74d
parent 3159
02cb2adb4868
child 3456
96232974dcdb
equal deleted inserted replaced
3174:86047f5f4155 3177:5af61402d74d
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (c) 2010 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2010 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 # Original (c) 2005-2010 Divmod, Inc. 5 # Original (c) 2005-2010 Divmod, Inc.
6 # 6 #
7 # This module is based on pyflakes for Python2 but was modified to 7 # This module is based on pyflakes but was modified to work with eric5
8 # work with eric5 8 """
9 9 Main module.
10 import os.path 10
11 Implement the central Checker class.
12 Also, it models the Bindings and Scopes.
13 """
14 import doctest
15 import os
16 import sys
11 try: 17 try:
12 import builtins 18 builtin_vars = dir(__import__('builtins'))
13 PY2 = False 19 PY2 = False
14 except ImportError: 20 except ImportError:
15 import __builtin__ as builtins #__IGNORE_WARNING__ 21 builtin_vars = dir(__import__('__builtin__'))
16 PY2 = True 22 PY2 = True
17 23
18 try: 24 try:
19 import ast 25 import ast
20 iter_child_nodes = ast.iter_child_nodes 26 iter_child_nodes = ast.iter_child_nodes
21 except (ImportError, AttributeError): # Python 2.5 27 except ImportError: # Python 2.5
22 import _ast as ast 28 import _ast as ast
23 29
24 def iter_child_nodes(node, astcls=ast.AST): 30 if 'decorator_list' not in ast.ClassDef._fields:
25 """ 31 # Patch the missing attribute 'decorator_list'
26 Yield all direct child nodes of *node*, that is, all fields that are nodes 32 ast.ClassDef.decorator_list = ()
27 and all items of fields that are lists of nodes. 33 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.
28 """ 39 """
29 for name in node._fields: 40 for name in node._fields:
30 field = getattr(node, name, None) 41 field = getattr(node, name, None)
31 if isinstance(field, astcls): 42 if isinstance(field, ast.AST):
32 yield field 43 yield field
33 elif isinstance(field, list): 44 elif isinstance(field, list):
34 for item in field: 45 for item in field:
35 yield item 46 yield item
36 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally) 47 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
42 ast_TryFinally = ast.TryFinally 53 ast_TryFinally = ast.TryFinally
43 54
44 from . import messages 55 from . import messages
45 56
46 57
58 if PY2:
59 def getNodeType(node_class):
60 # workaround str.upper() which is locale-dependent
61 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__
62 else:
63 def getNodeType(node_class):
64 return node_class.__name__.upper()
65
66
47 class Binding(object): 67 class Binding(object):
48 """ 68 """
49 Represents the binding of a value to a name. 69 Represents the binding of a value to a name.
50 70
51 The checker uses this to keep track of which names have been bound and 71 The checker uses this to keep track of which names have been bound and
52 which names have not. See L{Assignment} for a special type of binding that 72 which names have not. See L{Assignment} for a special type of binding that
53 is checked with stricter rules. 73 is checked with stricter rules.
74
75 @ivar used: pair of (L{Scope}, line-number) indicating the scope and
76 line number that this binding was last used
54 """ 77 """
55 78
56 def __init__(self, name, source): 79 def __init__(self, name, source):
57 self.name = name 80 self.name = name
58 self.source = source 81 self.source = source
66 self.name, 89 self.name,
67 self.source.lineno, 90 self.source.lineno,
68 id(self)) 91 id(self))
69 92
70 93
71 class UnBinding(Binding):
72 """Created by the 'del' operator."""
73
74
75 class Importation(Binding): 94 class Importation(Binding):
76 """ 95 """
77 A binding created by an import statement. 96 A binding created by an import statement.
97
98 @ivar fullName: The complete name given to the import statement,
99 possibly including multiple dotted components.
100 @type fullName: C{str}
78 """ 101 """
79 def __init__(self, name, source): 102 def __init__(self, name, source):
80 self.fullName = name 103 self.fullName = name
81 name = name.split('.')[0] 104 name = name.split('.')[0]
82 super(Importation, self).__init__(name, source) 105 super(Importation, self).__init__(name, source)
138 return names 161 return names
139 162
140 163
141 class Scope(dict): 164 class Scope(dict):
142 importStarred = False # set to True when import * is found 165 importStarred = False # set to True when import * is found
143 usesLocals = False
144 166
145 def __repr__(self): 167 def __repr__(self):
146 return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self)) 168 scope_cls = self.__class__.__name__
169 return '<%s at 0x%x %s>' % (scope_cls, id(self), dict.__repr__(self))
147 170
148 171
149 class ClassScope(Scope): 172 class ClassScope(Scope):
150 pass 173 pass
151 174
152 175
153 class FunctionScope(Scope): 176 class FunctionScope(Scope):
154 """ 177 """
155 I represent a name scope for a function. 178 I represent a name scope for a function.
156 """ 179
180 @ivar globals: Names declared 'global' in this function.
181 """
182 usesLocals = False
183 alwaysUsed = set(['__tracebackhide__',
184 '__traceback_info__', '__traceback_supplement__'])
185
157 def __init__(self): 186 def __init__(self):
158 super(FunctionScope, self).__init__() 187 super(FunctionScope, self).__init__()
159 self.globals = {} 188 # Simplify: manage the special locals as globals
189 self.globals = self.alwaysUsed.copy()
190
191 def unusedAssignments(self):
192 """
193 Return a generator for the assignments which have not been used.
194 """
195 for name, binding in self.items():
196 if (not binding.used and name not in self.globals
197 and not self.usesLocals
198 and isinstance(binding, Assignment)):
199 yield name, binding
200
201
202 class GeneratorScope(Scope):
203 pass
160 204
161 205
162 class ModuleScope(Scope): 206 class ModuleScope(Scope):
163 pass 207 pass
164 208
177 221
178 222
179 class Checker(object): 223 class Checker(object):
180 """ 224 """
181 I check the cleanliness and sanity of Python code. 225 I check the cleanliness and sanity of Python code.
226
227 @ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
228 of the list are two-tuples. The first element is the callable passed
229 to L{deferFunction}. The second element is a copy of the scope stack
230 at the time L{deferFunction} was called.
231
232 @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
233 callables which are deferred assignment checks.
182 """ 234 """
183 235
184 nodeDepth = 0 236 nodeDepth = 0
237 offset = None
185 traceTree = False 238 traceTree = False
186 builtIns = set(dir(builtins)) | set(_MAGIC_GLOBALS) 239 withDoctest = ('PYFLAKES_NODOCTEST' not in os.environ)
240
241 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
242 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
243 if _customBuiltIns:
244 builtIns.update(_customBuiltIns.split(','))
245 del _customBuiltIns
187 246
188 def __init__(self, tree, filename='(none)', builtins=None): 247 def __init__(self, tree, filename='(none)', builtins=None):
248 self._nodeHandlers = {}
189 self._deferredFunctions = [] 249 self._deferredFunctions = []
190 self._deferredAssignments = [] 250 self._deferredAssignments = []
191 self.deadScopes = [] 251 self.deadScopes = []
192 self.messages = [] 252 self.messages = []
193 self.filename = filename 253 self.filename = filename
194 if builtins: 254 if builtins:
195 self.builtIns = self.builtIns.union(builtins) 255 self.builtIns = self.builtIns.union(builtins)
196 self.scopeStack = [ModuleScope()] 256 self.scopeStack = [ModuleScope()]
257 self.exceptHandlers = [()]
197 self.futuresAllowed = True 258 self.futuresAllowed = True
198 self.root = tree 259 self.root = tree
199 self.handleChildren(tree) 260 self.handleChildren(tree)
200 self.runDeferred(self._deferredFunctions) 261 self.runDeferred(self._deferredFunctions)
201 # Set _deferredFunctions to None so that deferFunction will fail 262 # Set _deferredFunctions to None so that deferFunction will fail
216 This is used for handling function bodies, which must be deferred 277 This is used for handling function bodies, which must be deferred
217 because code later in the file might modify the global scope. When 278 because code later in the file might modify the global scope. When
218 `callable` is called, the scope at the time this is called will be 279 `callable` is called, the scope at the time this is called will be
219 restored, however it will contain any new bindings added to it. 280 restored, however it will contain any new bindings added to it.
220 """ 281 """
221 self._deferredFunctions.append((callable, self.scopeStack[:])) 282 self._deferredFunctions.append((callable, self.scopeStack[:], self.offset))
222 283
223 def deferAssignment(self, callable): 284 def deferAssignment(self, callable):
224 """ 285 """
225 Schedule an assignment handler to be called just after deferred 286 Schedule an assignment handler to be called just after deferred
226 function handlers. 287 function handlers.
227 """ 288 """
228 self._deferredAssignments.append((callable, self.scopeStack[:])) 289 self._deferredAssignments.append((callable, self.scopeStack[:], self.offset))
229 290
230 def runDeferred(self, deferred): 291 def runDeferred(self, deferred):
231 """ 292 """
232 Run the callables in C{deferred} using their associated scope stack. 293 Run the callables in C{deferred} using their associated scope stack.
233 """ 294 """
234 for handler, scope in deferred: 295 for handler, scope, offset in deferred:
235 self.scopeStack = scope 296 self.scopeStack = scope
297 self.offset = offset
236 handler() 298 handler()
237 299
238 @property 300 @property
239 def scope(self): 301 def scope(self):
240 return self.scopeStack[-1] 302 return self.scopeStack[-1]
249 """ 311 """
250 for scope in self.deadScopes: 312 for scope in self.deadScopes:
251 export = isinstance(scope.get('__all__'), ExportBinding) 313 export = isinstance(scope.get('__all__'), ExportBinding)
252 if export: 314 if export:
253 all = scope['__all__'].names() 315 all = scope['__all__'].names()
254 if not scope.importStarred and os.path.basename(self.filename) != '__init__.py': 316 if not scope.importStarred and \
317 os.path.basename(self.filename) != '__init__.py':
255 # Look for possible mistakes in the export list 318 # Look for possible mistakes in the export list
256 undefined = set(all) - set(scope) 319 undefined = set(all) - set(scope)
257 for name in undefined: 320 for name in undefined:
258 self.report(messages.UndefinedExport, 321 self.report(messages.UndefinedExport,
259 scope['__all__'].source.lineno, name) 322 scope['__all__'].source, name)
260 else: 323 else:
261 all = [] 324 all = []
262 325
263 # Look for imported names that aren't used. 326 # Look for imported names that aren't used.
264 for importation in scope.values(): 327 for importation in scope.values():
265 if isinstance(importation, Importation): 328 if isinstance(importation, Importation):
266 if not importation.used and importation.name not in all: 329 if not importation.used and importation.name not in all:
267 self.report(messages.UnusedImport, 330 self.report(messages.UnusedImport,
268 importation.source.lineno, importation.name) 331 importation.source, importation.name)
269 332
270 def pushFunctionScope(self): 333 def pushScope(self, scopeClass=FunctionScope):
271 self.scopeStack.append(FunctionScope()) 334 self.scopeStack.append(scopeClass())
272 335
273 def pushClassScope(self): 336 def pushFunctionScope(self): # XXX Deprecated
274 self.scopeStack.append(ClassScope()) 337 self.pushScope(FunctionScope)
338
339 def pushClassScope(self): # XXX Deprecated
340 self.pushScope(ClassScope)
275 341
276 def report(self, messageClass, *args, **kwargs): 342 def report(self, messageClass, *args, **kwargs):
277 self.messages.append(messageClass(self.filename, *args, **kwargs)) 343 self.messages.append(messageClass(self.filename, *args, **kwargs))
278 344
279 def hasParent(self, node, kind): 345 def hasParent(self, node, kind):
339 if not isinstance(self.scope, ClassScope): 405 if not isinstance(self.scope, ClassScope):
340 for scope in self.scopeStack[::-1]: 406 for scope in self.scopeStack[::-1]:
341 existing = scope.get(value.name) 407 existing = scope.get(value.name)
342 if (isinstance(existing, Importation) 408 if (isinstance(existing, Importation)
343 and not existing.used 409 and not existing.used
344 and (not isinstance(value, Importation) or value.fullName == existing.fullName) 410 and (not isinstance(value, Importation) or
411 value.fullName == existing.fullName)
345 and reportRedef 412 and reportRedef
346 and not self.differentForks(node, existing.source)): 413 and not self.differentForks(node, existing.source)):
347 redefinedWhileUnused = True 414 redefinedWhileUnused = True
348 self.report(messages.RedefinedWhileUnused, 415 self.report(messages.RedefinedWhileUnused,
349 node.lineno, value.name, existing.source.lineno) 416 node, value.name, existing.source)
350 417
351 existing = self.scope.get(value.name) 418 existing = self.scope.get(value.name)
352 if not redefinedWhileUnused and self.hasParent(value.source, ast.ListComp): 419 if not redefinedWhileUnused and self.hasParent(value.source, ast.ListComp):
353 if (existing and reportRedef 420 if (existing and reportRedef
354 and not self.hasParent(existing.source, (ast.For, ast.ListComp))): 421 and not self.hasParent(existing.source, (ast.For, ast.ListComp))
422 and not self.differentForks(node, existing.source)):
355 self.report(messages.RedefinedInListComp, 423 self.report(messages.RedefinedInListComp,
356 node.lineno, value.name, existing.source.lineno) 424 node, value.name, existing.source)
357 425
358 if isinstance(value, UnBinding): 426 if (isinstance(existing, Definition)
359 try: 427 and not existing.used
360 del self.scope[value.name] 428 and not self.differentForks(node, existing.source)):
361 except KeyError:
362 self.report(messages.UndefinedName, node.lineno, value.name)
363 elif (isinstance(existing, Definition)
364 and not existing.used
365 and not self.differentForks(node, existing.source)):
366 self.report(messages.RedefinedWhileUnused, 429 self.report(messages.RedefinedWhileUnused,
367 node.lineno, value.name, existing.source.lineno) 430 node, value.name, existing.source)
368 else: 431 else:
369 self.scope[value.name] = value 432 self.scope[value.name] = value
433
434 def getNodeHandler(self, node_class):
435 try:
436 return self._nodeHandlers[node_class]
437 except KeyError:
438 nodeType = getNodeType(node_class)
439 self._nodeHandlers[node_class] = handler = getattr(self, nodeType)
440 return handler
370 441
371 def handleNodeLoad(self, node): 442 def handleNodeLoad(self, node):
372 name = getNodeName(node) 443 name = getNodeName(node)
373 if not name: 444 if not name:
374 return 445 return
375 # try local scope 446 # try local scope
376 importStarred = self.scope.importStarred
377 try: 447 try:
378 self.scope[name].used = (self.scope, node.lineno) 448 self.scope[name].used = (self.scope, node)
379 except KeyError: 449 except KeyError:
380 pass 450 pass
381 else: 451 else:
382 return 452 return
383 453
384 # try enclosing function scopes 454 scopes = [scope for scope in self.scopeStack[:-1]
385 for scope in self.scopeStack[-2:0:-1]: 455 if isinstance(scope, (FunctionScope, ModuleScope))]
456 if isinstance(self.scope, GeneratorScope) and scopes[-1] != self.scopeStack[-2]:
457 scopes.append(self.scopeStack[-2])
458
459 # try enclosing function scopes and global scope
460 importStarred = self.scope.importStarred
461 for scope in reversed(scopes):
386 importStarred = importStarred or scope.importStarred 462 importStarred = importStarred or scope.importStarred
387 if not isinstance(scope, FunctionScope):
388 continue
389 try: 463 try:
390 scope[name].used = (self.scope, node.lineno) 464 scope[name].used = (self.scope, node)
391 except KeyError: 465 except KeyError:
392 pass 466 pass
393 else: 467 else:
394 return 468 return
395 469
396 # try global scope 470 # look in the built-ins
397 importStarred = importStarred or self.scopeStack[0].importStarred 471 if importStarred or name in self.builtIns:
398 try: 472 return
399 self.scopeStack[0][name].used = (self.scope, node.lineno) 473 if name == '__path__' and os.path.basename(self.filename) == '__init__.py':
400 except KeyError: 474 # the special name __path__ is valid only in packages
401 if not importStarred and name not in self.builtIns: 475 return
402 if (os.path.basename(self.filename) == '__init__.py' and name == '__path__'): 476
403 # the special name __path__ is valid only in packages 477 # protected with a NameError handler?
404 pass 478 if 'NameError' not in self.exceptHandlers[-1]:
405 else: 479 self.report(messages.UndefinedName, node, name)
406 self.report(messages.UndefinedName, node.lineno, name)
407 480
408 def handleNodeStore(self, node): 481 def handleNodeStore(self, node):
409 name = getNodeName(node) 482 name = getNodeName(node)
410 if not name: 483 if not name:
411 return 484 return
416 if not isinstance(scope, (FunctionScope, ModuleScope)): 489 if not isinstance(scope, (FunctionScope, ModuleScope)):
417 continue 490 continue
418 # if the name was defined in that scope, and the name has 491 # if the name was defined in that scope, and the name has
419 # been accessed already in the current scope, and hasn't 492 # been accessed already in the current scope, and hasn't
420 # been declared global 493 # been declared global
421 if (name in scope and scope[name].used and scope[name].used[0] is self.scope 494 used = name in scope and scope[name].used
422 and name not in self.scope.globals): 495 if used and used[0] is self.scope and name not in self.scope.globals:
423 # then it's probably a mistake 496 # then it's probably a mistake
424 self.report(messages.UndefinedLocal, 497 self.report(messages.UndefinedLocal,
425 scope[name].used[1], name, scope[name].source.lineno) 498 scope[name].used[1], name, scope[name].source)
426 break 499 break
427 500
428 parent = getattr(node, 'parent', None) 501 parent = getattr(node, 'parent', None)
429 if isinstance(parent, (ast.For, ast.comprehension, ast.Tuple, ast.List)): 502 if isinstance(parent, (ast.For, ast.comprehension, ast.Tuple, ast.List)):
430 binding = Binding(name, node) 503 binding = Binding(name, node)
431 elif parent is not None and name == '__all__' and isinstance(self.scope, ModuleScope): 504 elif (parent is not None and name == '__all__' and
505 isinstance(self.scope, ModuleScope)):
432 binding = ExportBinding(name, parent.value) 506 binding = ExportBinding(name, parent.value)
433 else: 507 else:
434 binding = Assignment(name, node) 508 binding = Assignment(name, node)
435 if name in self.scope: 509 if name in self.scope:
436 binding.used = self.scope[name].used 510 binding.used = self.scope[name].used
439 def handleNodeDelete(self, node): 513 def handleNodeDelete(self, node):
440 name = getNodeName(node) 514 name = getNodeName(node)
441 if not name: 515 if not name:
442 return 516 return
443 if isinstance(self.scope, FunctionScope) and name in self.scope.globals: 517 if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
444 del self.scope.globals[name] 518 self.scope.globals.remove(name)
445 else: 519 else:
446 self.addBinding(node, UnBinding(name, node)) 520 try:
521 del self.scope[name]
522 except KeyError:
523 self.report(messages.UndefinedName, node, name)
447 524
448 def handleChildren(self, tree): 525 def handleChildren(self, tree):
449 for node in iter_child_nodes(tree): 526 for node in iter_child_nodes(tree):
450 self.handleNode(node, tree) 527 self.handleNode(node, tree)
451 528
455 correct place in the node tree. 532 correct place in the node tree.
456 """ 533 """
457 return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and 534 return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and
458 isinstance(node.value, ast.Str)) 535 isinstance(node.value, ast.Str))
459 536
537 def getDocstring(self, node):
538 if isinstance(node, ast.Expr):
539 node = node.value
540 if not isinstance(node, ast.Str):
541 return (None, None)
542 # Computed incorrectly if the docstring has backslash
543 doctest_lineno = node.lineno - node.s.count('\n') - 1
544 return (node.s, doctest_lineno)
545
460 def handleNode(self, node, parent): 546 def handleNode(self, node, parent):
461 if node is None: 547 if node is None:
462 return 548 return
463 node.parent = parent 549 if self.offset and getattr(node, 'lineno', None) is not None:
550 node.lineno += self.offset[0]
551 node.col_offset += self.offset[1]
464 if self.traceTree: 552 if self.traceTree:
465 print(' ' * self.nodeDepth + node.__class__.__name__) 553 print(' ' * self.nodeDepth + node.__class__.__name__)
466 self.nodeDepth += 1
467 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or 554 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or
468 self.isDocstring(node)): 555 self.isDocstring(node)):
469 self.futuresAllowed = False 556 self.futuresAllowed = False
470 nodeType = node.__class__.__name__.upper() 557 self.nodeDepth += 1
471 node.level = self.nodeDepth 558 node.level = self.nodeDepth
559 node.parent = parent
472 try: 560 try:
473 handler = getattr(self, nodeType) 561 handler = self.getNodeHandler(node.__class__)
474 handler(node) 562 handler(node)
475 finally: 563 finally:
476 self.nodeDepth -= 1 564 self.nodeDepth -= 1
477 if self.traceTree: 565 if self.traceTree:
478 print(' ' * self.nodeDepth + 'end ' + node.__class__.__name__) 566 print(' ' * self.nodeDepth + 'end ' + node.__class__.__name__)
479 567
568 _getDoctestExamples = doctest.DocTestParser().get_examples
569
570 def handleDoctests(self, node):
571 try:
572 docstring, node_lineno = self.getDocstring(node.body[0])
573 if not docstring:
574 return
575 examples = self._getDoctestExamples(docstring)
576 except (ValueError, IndexError):
577 # e.g. line 6 of the docstring for <string> has inconsistent
578 # leading whitespace: ...
579 return
580 node_offset = self.offset or (0, 0)
581 self.pushScope()
582 for example in examples:
583 try:
584 tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST)
585 except SyntaxError:
586 e = sys.exc_info()[1]
587 position = (node_lineno + example.lineno + e.lineno,
588 example.indent + 4 + e.offset)
589 self.report(messages.DoctestSyntaxError, node, position)
590 else:
591 self.offset = (node_offset[0] + node_lineno + example.lineno,
592 node_offset[1] + example.indent + 4)
593 self.handleChildren(tree)
594 self.offset = node_offset
595 self.popScope()
596
480 def ignore(self, node): 597 def ignore(self, node):
481 pass 598 pass
482 599
483 # "stmt" type nodes 600 # "stmt" type nodes
484 RETURN = DELETE = PRINT = WHILE = IF = WITH = WITHITEM = RAISE = \ 601 RETURN = DELETE = PRINT = WHILE = IF = WITH = WITHITEM = RAISE = \
485 TRYEXCEPT = TRYFINALLY = TRY = ASSERT = EXEC = EXPR = handleChildren 602 TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren
486 603
487 CONTINUE = BREAK = PASS = ignore 604 CONTINUE = BREAK = PASS = ignore
488 605
489 # "expr" type nodes 606 # "expr" type nodes
490 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = YIELDFROM = \ 607 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = YIELDFROM = \
510 def GLOBAL(self, node): 627 def GLOBAL(self, node):
511 """ 628 """
512 Keep track of globals declarations. 629 Keep track of globals declarations.
513 """ 630 """
514 if isinstance(self.scope, FunctionScope): 631 if isinstance(self.scope, FunctionScope):
515 self.scope.globals.update(dict.fromkeys(node.names)) 632 self.scope.globals.update(node.names)
516 633
517 NONLOCAL = GLOBAL 634 NONLOCAL = GLOBAL
518 635
519 def LISTCOMP(self, node): 636 def LISTCOMP(self, node):
520 # handle generators before element 637 # handle generators before element
521 for gen in node.generators: 638 for gen in node.generators:
522 self.handleNode(gen, node) 639 self.handleNode(gen, node)
523 self.handleNode(node.elt, node) 640 self.handleNode(node.elt, node)
524 641
525 GENERATOREXP = SETCOMP = LISTCOMP 642 def GENERATOREXP(self, node):
643 self.pushScope(GeneratorScope)
644 # handle generators before element
645 for gen in node.generators:
646 self.handleNode(gen, node)
647 self.handleNode(node.elt, node)
648 self.popScope()
649
650 SETCOMP = GENERATOREXP
526 651
527 def DICTCOMP(self, node): 652 def DICTCOMP(self, node):
653 self.pushScope(GeneratorScope)
528 for gen in node.generators: 654 for gen in node.generators:
529 self.handleNode(gen, node) 655 self.handleNode(gen, node)
530 self.handleNode(node.key, node) 656 self.handleNode(node.key, node)
531 self.handleNode(node.value, node) 657 self.handleNode(node.value, node)
658 self.popScope()
532 659
533 def FOR(self, node): 660 def FOR(self, node):
534 """ 661 """
535 Process bindings for loop variables. 662 Process bindings for loop variables.
536 """ 663 """
549 for varn in vars: 676 for varn in vars:
550 if (isinstance(self.scope.get(varn), Importation) 677 if (isinstance(self.scope.get(varn), Importation)
551 # unused ones will get an unused import warning 678 # unused ones will get an unused import warning
552 and self.scope[varn].used): 679 and self.scope[varn].used):
553 self.report(messages.ImportShadowedByLoopVar, 680 self.report(messages.ImportShadowedByLoopVar,
554 node.lineno, varn, self.scope[varn].source.lineno) 681 node, varn, self.scope[varn].source)
555 682
556 self.handleChildren(node) 683 self.handleChildren(node)
557 684
558 def NAME(self, node): 685 def NAME(self, node):
559 """ 686 """
560 Handle occurrence of Name (which can be a load/store/delete access.) 687 Handle occurrence of Name (which can be a load/store/delete access.)
561 """ 688 """
562 if node.id == 'locals' and isinstance(node.parent, ast.Call):
563 # we are doing locals() call in current scope
564 self.scope.usesLocals = True
565 # Locate the name in locals / function / globals scopes. 689 # Locate the name in locals / function / globals scopes.
566 if isinstance(node.ctx, (ast.Load, ast.AugLoad)): 690 if isinstance(node.ctx, (ast.Load, ast.AugLoad)):
567 self.handleNodeLoad(node) 691 self.handleNodeLoad(node)
692 if (node.id == 'locals' and isinstance(self.scope, FunctionScope)
693 and isinstance(node.parent, ast.Call)):
694 # we are doing locals() call in current scope
695 self.scope.usesLocals = True
568 elif isinstance(node.ctx, (ast.Store, ast.AugStore)): 696 elif isinstance(node.ctx, (ast.Store, ast.AugStore)):
569 self.handleNodeStore(node) 697 self.handleNodeStore(node)
570 elif isinstance(node.ctx, ast.Del): 698 elif isinstance(node.ctx, ast.Del):
571 self.handleNodeDelete(node) 699 self.handleNodeDelete(node)
572 else: 700 else:
573 # must be a Param context -- this only happens for names in function 701 # must be a Param context -- this only happens for names in function
574 # arguments, but these aren't dispatched through here 702 # arguments, but these aren't dispatched through here
575 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) 703 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
576 704
577 def FUNCTIONDEF(self, node): 705 def FUNCTIONDEF(self, node):
578 if not hasattr(node, 'decorator_list'): # Python 2.5
579 node.decorator_list = node.decorators
580 for deco in node.decorator_list: 706 for deco in node.decorator_list:
581 self.handleNode(deco, node) 707 self.handleNode(deco, node)
582 self.addBinding(node, FunctionDefinition(node.name, node)) 708 self.addBinding(node, FunctionDefinition(node.name, node))
583 self.LAMBDA(node) 709 self.LAMBDA(node)
710 if self.withDoctest:
711 self.deferFunction(lambda: self.handleDoctests(node))
584 712
585 def LAMBDA(self, node): 713 def LAMBDA(self, node):
586 args = [] 714 args = []
587 715
588 if PY2: 716 if PY2:
591 if isinstance(arg, ast.Tuple): 719 if isinstance(arg, ast.Tuple):
592 addArgs(arg.elts) 720 addArgs(arg.elts)
593 else: 721 else:
594 if arg.id in args: 722 if arg.id in args:
595 self.report(messages.DuplicateArgument, 723 self.report(messages.DuplicateArgument,
596 node.lineno, arg.id) 724 node, arg.id)
597 args.append(arg.id) 725 args.append(arg.id)
598 addArgs(node.args.args) 726 addArgs(node.args.args)
599 defaults = node.args.defaults 727 defaults = node.args.defaults
600 else: 728 else:
601 for arg in node.args.args + node.args.kwonlyargs: 729 for arg in node.args.args + node.args.kwonlyargs:
602 if arg.arg in args: 730 if arg.arg in args:
603 self.report(messages.DuplicateArgument, 731 self.report(messages.DuplicateArgument,
604 node.lineno, arg.arg) 732 node, arg.arg)
605 args.append(arg.arg) 733 args.append(arg.arg)
606 self.handleNode(arg.annotation, node) 734 self.handleNode(arg.annotation, node)
607 if hasattr(node, 'returns'): # Only for FunctionDefs 735 if hasattr(node, 'returns'): # Only for FunctionDefs
608 for annotation in (node.args.varargannotation, 736 for annotation in (node.args.varargannotation,
609 node.args.kwargannotation, node.returns): 737 node.args.kwargannotation, node.returns):
613 # vararg/kwarg identifiers are not Name nodes 741 # vararg/kwarg identifiers are not Name nodes
614 for wildcard in (node.args.vararg, node.args.kwarg): 742 for wildcard in (node.args.vararg, node.args.kwarg):
615 if not wildcard: 743 if not wildcard:
616 continue 744 continue
617 if wildcard in args: 745 if wildcard in args:
618 self.report(messages.DuplicateArgument, node.lineno, wildcard) 746 self.report(messages.DuplicateArgument, node, wildcard)
619 args.append(wildcard) 747 args.append(wildcard)
620 for default in defaults: 748 for default in defaults:
621 self.handleNode(default, node) 749 self.handleNode(default, node)
622 750
623 def runFunction(): 751 def runFunction():
624 752
625 self.pushFunctionScope() 753 self.pushScope()
626 for name in args: 754 for name in args:
627 self.addBinding(node, Argument(name, node), reportRedef=False) 755 self.addBinding(node, Argument(name, node), reportRedef=False)
628 if isinstance(node.body, list): 756 if isinstance(node.body, list):
629 # case for FunctionDefs 757 # case for FunctionDefs
630 for stmt in node.body: 758 for stmt in node.body:
635 763
636 def checkUnusedAssignments(): 764 def checkUnusedAssignments():
637 """ 765 """
638 Check to see if any assignments have not been used. 766 Check to see if any assignments have not been used.
639 """ 767 """
640 for name, binding in self.scope.items(): 768 for name, binding in self.scope.unusedAssignments():
641 if (not binding.used and name not in self.scope.globals 769 self.report(messages.UnusedVariable, binding.source, name)
642 and not self.scope.usesLocals
643 and isinstance(binding, Assignment)):
644 self.report(messages.UnusedVariable,
645 binding.source.lineno, name)
646 self.deferAssignment(checkUnusedAssignments) 770 self.deferAssignment(checkUnusedAssignments)
647 self.popScope() 771 self.popScope()
648 772
649 self.deferFunction(runFunction) 773 self.deferFunction(runFunction)
650 774
652 """ 776 """
653 Check names used in a class definition, including its decorators, base 777 Check names used in a class definition, including its decorators, base
654 classes, and the body of its definition. Additionally, add its name to 778 classes, and the body of its definition. Additionally, add its name to
655 the current scope. 779 the current scope.
656 """ 780 """
657 # no class decorator in Python 2.5 781 for deco in node.decorator_list:
658 for deco in getattr(node, 'decorator_list', ''):
659 self.handleNode(deco, node) 782 self.handleNode(deco, node)
660 for baseNode in node.bases: 783 for baseNode in node.bases:
661 self.handleNode(baseNode, node) 784 self.handleNode(baseNode, node)
662 if not PY2: 785 if not PY2:
663 for keywordNode in node.keywords: 786 for keywordNode in node.keywords:
664 self.handleNode(keywordNode, node) 787 self.handleNode(keywordNode, node)
665 self.pushClassScope() 788 self.pushScope(ClassScope)
789 if self.withDoctest:
790 self.deferFunction(lambda: self.handleDoctests(node))
666 for stmt in node.body: 791 for stmt in node.body:
667 self.handleNode(stmt, node) 792 self.handleNode(stmt, node)
668 self.popScope() 793 self.popScope()
669 self.addBinding(node, ClassDefinition(node.name, node)) 794 self.addBinding(node, ClassDefinition(node.name, node))
670 795
686 811
687 def IMPORTFROM(self, node): 812 def IMPORTFROM(self, node):
688 if node.module == '__future__': 813 if node.module == '__future__':
689 if not self.futuresAllowed: 814 if not self.futuresAllowed:
690 self.report(messages.LateFutureImport, 815 self.report(messages.LateFutureImport,
691 node.lineno, [n.name for n in node.names]) 816 node, [n.name for n in node.names])
692 else: 817 else:
693 self.futuresAllowed = False 818 self.futuresAllowed = False
694 819
695 for alias in node.names: 820 for alias in node.names:
696 if alias.name == '*': 821 if alias.name == '*':
697 self.scope.importStarred = True 822 self.scope.importStarred = True
698 self.report(messages.ImportStarUsed, node.lineno, node.module) 823 self.report(messages.ImportStarUsed, node, node.module)
699 continue 824 continue
700 name = alias.asname or alias.name 825 name = alias.asname or alias.name
701 importation = Importation(name, node) 826 importation = Importation(name, node)
702 if node.module == '__future__': 827 if node.module == '__future__':
703 importation.used = (self.scope, node.lineno) 828 importation.used = (self.scope, node)
704 self.addBinding(node, importation) 829 self.addBinding(node, importation)
830
831 def TRY(self, node):
832 handler_names = []
833 # List the exception handlers
834 for handler in node.handlers:
835 if isinstance(handler.type, ast.Tuple):
836 for exc_type in handler.type.elts:
837 handler_names.append(getNodeName(exc_type))
838 elif handler.type:
839 handler_names.append(getNodeName(handler.type))
840 # Memorize the except handlers and process the body
841 self.exceptHandlers.append(handler_names)
842 for child in node.body:
843 self.handleNode(child, node)
844 self.exceptHandlers.pop()
845 # Process the other nodes: "except:", "else:", "finally:"
846 for child in iter_child_nodes(node):
847 if child not in node.body:
848 self.handleNode(child, node)
849
850 TRYEXCEPT = TRY
705 851
706 def EXCEPTHANDLER(self, node): 852 def EXCEPTHANDLER(self, node):
707 # 3.x: in addition to handling children, we must handle the name of 853 # 3.x: in addition to handling children, we must handle the name of
708 # the exception, which is not a Name node, but a simple string. 854 # the exception, which is not a Name node, but a simple string.
709 if isinstance(node.name, str): 855 if isinstance(node.name, str):

eric ide

mercurial