@@ -394,9 +394,13 @@ def __init__(self, name, source, scope):
394
394
class Scope (dict ):
395
395
importStarred = False # set to True when import * is found
396
396
397
+ def __init__ (self , node ):
398
+ self .node = node
399
+
397
400
def __repr__ (self ):
398
401
scope_cls = self .__class__ .__name__
399
- return '<%s at 0x%x %s>' % (scope_cls , id (self ), dict .__repr__ (self ))
402
+ return '<%s at 0x%x for %r containing: %s>' % (
403
+ scope_cls , id (self ), self .node , dict .__repr__ (self ))
400
404
401
405
402
406
class ClassScope (Scope ):
@@ -413,8 +417,8 @@ class FunctionScope(Scope):
413
417
alwaysUsed = {'__tracebackhide__' , '__traceback_info__' ,
414
418
'__traceback_supplement__' }
415
419
416
- def __init__ (self ):
417
- super (FunctionScope , self ).__init__ ()
420
+ def __init__ (self , node ):
421
+ super (FunctionScope , self ).__init__ (node )
418
422
# Simplify: manage the special locals as globals
419
423
self .globals = self .alwaysUsed .copy ()
420
424
self .returnValue = None # First non-empty return
@@ -491,8 +495,9 @@ def __init__(self, tree, filename='(none)', builtins=None,
491
495
if builtins :
492
496
self .builtIns = self .builtIns .union (builtins )
493
497
self .withDoctest = withDoctest
494
- self .scopeStack = [ModuleScope ()]
498
+ self .scopeStack = [ModuleScope (tree )]
495
499
self .exceptHandlers = [()]
500
+ tree .depth = self .nodeDepth
496
501
self .root = tree
497
502
self .handleChildren (tree )
498
503
self .runDeferred (self ._deferredFunctions )
@@ -609,8 +614,8 @@ def checkDeadScopes(self):
609
614
messg = messages .RedefinedWhileUnused
610
615
self .report (messg , node , value .name , value .source )
611
616
612
- def pushScope (self , scopeClass = FunctionScope ):
613
- self .scopeStack .append (scopeClass ())
617
+ def pushScope (self , scopeClass = FunctionScope , node = None ):
618
+ self .scopeStack .append (scopeClass (node ))
614
619
615
620
def report (self , messageClass , * args , ** kwargs ):
616
621
self .messages .append (messageClass (self .filename , * args , ** kwargs ))
@@ -629,6 +634,9 @@ def getCommonAncestor(self, lnode, rnode, stop):
629
634
if lnode is rnode :
630
635
return lnode
631
636
637
+ if stop .depth in (lnode .depth , rnode .depth ):
638
+ return None
639
+
632
640
if (lnode .depth > rnode .depth ):
633
641
return self .getCommonAncestor (lnode .parent , rnode , stop )
634
642
if (lnode .depth < rnode .depth ):
@@ -643,7 +651,8 @@ def descendantOf(self, node, ancestors, stop):
643
651
644
652
def differentForks (self , lnode , rnode ):
645
653
"""True, if lnode and rnode are located on different forks of IF/TRY"""
646
- ancestor = self .getCommonAncestor (lnode , rnode , self .root )
654
+ ancestor = self .getCommonAncestor (lnode , rnode ,
655
+ self .scope .node or self .root )
647
656
parts = getAlternatives (ancestor )
648
657
if parts :
649
658
for items in parts :
@@ -665,15 +674,19 @@ def addBinding(self, node, value):
665
674
break
666
675
existing = scope .get (value .name )
667
676
668
- if existing and not self . differentForks ( node , existing . source ) :
677
+ if existing :
669
678
670
679
parent_stmt = self .getParent (value .source )
671
680
if isinstance (existing , Importation ) and isinstance (parent_stmt , ast .For ):
672
681
self .report (messages .ImportShadowedByLoopVar ,
673
682
node , value .name , existing .source )
674
683
675
684
elif scope is self .scope :
676
- if (isinstance (parent_stmt , ast .comprehension ) and
685
+ if self .differentForks (node , existing .source ):
686
+ # ignore redefinitions in different forks of `if` & `try`
687
+ pass
688
+
689
+ elif (isinstance (parent_stmt , ast .comprehension ) and
677
690
not isinstance (self .getParent (existing .source ),
678
691
(ast .For , ast .comprehension ))):
679
692
self .report (messages .RedefinedInListComp ,
@@ -903,7 +916,7 @@ def handleDoctests(self, node):
903
916
saved_stack = self .scopeStack
904
917
self .scopeStack = [self .scopeStack [0 ]]
905
918
node_offset = self .offset or (0 , 0 )
906
- self .pushScope (DoctestScope )
919
+ self .pushScope (DoctestScope , node )
907
920
underscore_in_builtins = '_' in self .builtIns
908
921
if not underscore_in_builtins :
909
922
self .builtIns .add ('_' )
@@ -1079,7 +1092,7 @@ def GLOBAL(self, node):
1079
1092
NONLOCAL = GLOBAL
1080
1093
1081
1094
def GENERATOREXP (self , node ):
1082
- self .pushScope (GeneratorScope )
1095
+ self .pushScope (GeneratorScope , node )
1083
1096
self .handleChildren (node )
1084
1097
self .popScope ()
1085
1098
@@ -1219,7 +1232,7 @@ def addArgs(arglist):
1219
1232
1220
1233
def runFunction ():
1221
1234
1222
- self .pushScope ()
1235
+ self .pushScope (FunctionScope , node )
1223
1236
for name in args :
1224
1237
self .addBinding (node , Argument (name , node ))
1225
1238
if isinstance (node .body , list ):
@@ -1265,7 +1278,7 @@ def CLASSDEF(self, node):
1265
1278
if not PY2 :
1266
1279
for keywordNode in node .keywords :
1267
1280
self .handleNode (keywordNode , node )
1268
- self .pushScope (ClassScope )
1281
+ self .pushScope (ClassScope , node )
1269
1282
# doctest does not process doctest within a doctest
1270
1283
# classes within classes are processed.
1271
1284
if (self .withDoctest and
0 commit comments