@@ -394,9 +394,13 @@ def __init__(self, name, source, scope):
394394class Scope (dict ):
395395 importStarred = False # set to True when import * is found
396396
397+ def __init__ (self , node ):
398+ self .node = node
399+
397400 def __repr__ (self ):
398401 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 ))
400404
401405
402406class ClassScope (Scope ):
@@ -413,8 +417,8 @@ class FunctionScope(Scope):
413417 alwaysUsed = {'__tracebackhide__' , '__traceback_info__' ,
414418 '__traceback_supplement__' }
415419
416- def __init__ (self ):
417- super (FunctionScope , self ).__init__ ()
420+ def __init__ (self , node ):
421+ super (FunctionScope , self ).__init__ (node )
418422 # Simplify: manage the special locals as globals
419423 self .globals = self .alwaysUsed .copy ()
420424 self .returnValue = None # First non-empty return
@@ -491,7 +495,8 @@ def __init__(self, tree, filename='(none)', builtins=None,
491495 if builtins :
492496 self .builtIns = self .builtIns .union (builtins )
493497 self .withDoctest = withDoctest
494- self .scopeStack = [ModuleScope ()]
498+ tree .depth = self .nodeDepth
499+ self .scopeStack = [ModuleScope (tree )]
495500 self .exceptHandlers = [()]
496501 self .root = tree
497502 self .handleChildren (tree )
@@ -609,8 +614,8 @@ def checkDeadScopes(self):
609614 messg = messages .RedefinedWhileUnused
610615 self .report (messg , node , value .name , value .source )
611616
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 ))
614619
615620 def report (self , messageClass , * args , ** kwargs ):
616621 self .messages .append (messageClass (self .filename , * args , ** kwargs ))
@@ -629,6 +634,9 @@ def getCommonAncestor(self, lnode, rnode, stop):
629634 if lnode is rnode :
630635 return lnode
631636
637+ if stop .depth in (lnode .depth , rnode .depth ):
638+ return None
639+
632640 if (lnode .depth > rnode .depth ):
633641 return self .getCommonAncestor (lnode .parent , rnode , stop )
634642 if (lnode .depth < rnode .depth ):
@@ -643,7 +651,8 @@ def descendantOf(self, node, ancestors, stop):
643651
644652 def differentForks (self , lnode , rnode ):
645653 """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 )
647656 parts = getAlternatives (ancestor )
648657 if parts :
649658 for items in parts :
@@ -665,15 +674,19 @@ def addBinding(self, node, value):
665674 break
666675 existing = scope .get (value .name )
667676
668- if existing and not self . differentForks ( node , existing . source ) :
677+ if existing :
669678
670679 parent_stmt = self .getParent (value .source )
671680 if isinstance (existing , Importation ) and isinstance (parent_stmt , ast .For ):
672681 self .report (messages .ImportShadowedByLoopVar ,
673682 node , value .name , existing .source )
674683
675684 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
677690 not isinstance (self .getParent (existing .source ),
678691 (ast .For , ast .comprehension ))):
679692 self .report (messages .RedefinedInListComp ,
@@ -903,7 +916,7 @@ def handleDoctests(self, node):
903916 saved_stack = self .scopeStack
904917 self .scopeStack = [self .scopeStack [0 ]]
905918 node_offset = self .offset or (0 , 0 )
906- self .pushScope (DoctestScope )
919+ self .pushScope (DoctestScope , node )
907920 underscore_in_builtins = '_' in self .builtIns
908921 if not underscore_in_builtins :
909922 self .builtIns .add ('_' )
@@ -1079,7 +1092,7 @@ def GLOBAL(self, node):
10791092 NONLOCAL = GLOBAL
10801093
10811094 def GENERATOREXP (self , node ):
1082- self .pushScope (GeneratorScope )
1095+ self .pushScope (GeneratorScope , node )
10831096 self .handleChildren (node )
10841097 self .popScope ()
10851098
@@ -1219,7 +1232,7 @@ def addArgs(arglist):
12191232
12201233 def runFunction ():
12211234
1222- self .pushScope ()
1235+ self .pushScope (FunctionScope , node )
12231236 for name in args :
12241237 self .addBinding (node , Argument (name , node ))
12251238 if isinstance (node .body , list ):
@@ -1265,7 +1278,7 @@ def CLASSDEF(self, node):
12651278 if not PY2 :
12661279 for keywordNode in node .keywords :
12671280 self .handleNode (keywordNode , node )
1268- self .pushScope (ClassScope )
1281+ self .pushScope (ClassScope , node )
12691282 # doctest does not process doctest within a doctest
12701283 # classes within classes are processed.
12711284 if (self .withDoctest and
0 commit comments