@@ -448,6 +448,10 @@ def addBinding(self, node, value):
448448 elif isinstance (existing , Importation ) and value .redefines (existing ):
449449 existing .redefined .append (node )
450450
451+ if value .name in self .scope :
452+ # then assume the rebound name is used as a global or within a loop
453+ value .used = self .scope [value .name ].used
454+
451455 self .scope [value .name ] = value
452456
453457 def getNodeHandler (self , node_class ):
@@ -471,7 +475,7 @@ def handleNodeLoad(self, node):
471475 return
472476
473477 scopes = [scope for scope in self .scopeStack [:- 1 ]
474- if isinstance (scope , (FunctionScope , ModuleScope ))]
478+ if isinstance (scope , (FunctionScope , ModuleScope , GeneratorScope ))]
475479 if isinstance (self .scope , GeneratorScope ) and scopes [- 1 ] != self .scopeStack [- 2 ]:
476480 scopes .append (self .scopeStack [- 2 ])
477481
@@ -526,14 +530,30 @@ def handleNodeStore(self, node):
526530 binding = ExportBinding (name , node .parent , self .scope )
527531 else :
528532 binding = Assignment (name , node )
529- if name in self .scope :
530- binding .used = self .scope [name ].used
531533 self .addBinding (node , binding )
532534
533535 def handleNodeDelete (self , node ):
536+
537+ def on_conditional_branch ():
538+ """
539+ Return `True` if node is part of a conditional body.
540+ """
541+ current = getattr (node , 'parent' , None )
542+ while current :
543+ if isinstance (current , (ast .If , ast .While , ast .IfExp )):
544+ return True
545+ current = getattr (current , 'parent' , None )
546+ return False
547+
534548 name = getNodeName (node )
535549 if not name :
536550 return
551+
552+ if on_conditional_branch ():
553+ # We can not predict if this conditional branch is going to
554+ # be executed.
555+ return
556+
537557 if isinstance (self .scope , FunctionScope ) and name in self .scope .globals :
538558 self .scope .globals .remove (name )
539559 else :
@@ -630,8 +650,9 @@ def ignore(self, node):
630650 pass
631651
632652 # "stmt" type nodes
633- DELETE = PRINT = FOR = WHILE = IF = WITH = WITHITEM = RAISE = \
634- TRYFINALLY = ASSERT = EXEC = EXPR = ASSIGN = handleChildren
653+ DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
654+ ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = ASSERT = EXEC = \
655+ EXPR = ASSIGN = handleChildren
635656
636657 CONTINUE = BREAK = PASS = ignore
637658
@@ -654,14 +675,36 @@ def ignore(self, node):
654675 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
655676
656677 # additional node types
657- LISTCOMP = COMPREHENSION = KEYWORD = handleChildren
678+ COMPREHENSION = KEYWORD = handleChildren
658679
659680 def GLOBAL (self , node ):
660681 """
661682 Keep track of globals declarations.
662683 """
663- if isinstance (self .scope , FunctionScope ):
664- self .scope .globals .update (node .names )
684+ # In doctests, the global scope is an anonymous function at index 1.
685+ global_scope_index = 1 if self .withDoctest else 0
686+ global_scope = self .scopeStack [global_scope_index ]
687+
688+ # Ignore 'global' statement in global scope.
689+ if self .scope is not global_scope :
690+
691+ # One 'global' statement can bind multiple (comma-delimited) names.
692+ for node_name in node .names :
693+ node_value = Assignment (node_name , node )
694+
695+ # Remove UndefinedName messages already reported for this name.
696+ self .messages = [
697+ m for m in self .messages if not
698+ isinstance (m , messages .UndefinedName ) and not
699+ m .message_args [0 ] == node_name ]
700+
701+ # Bind name to global scope if it doesn't exist already.
702+ global_scope .setdefault (node_name , node_value )
703+
704+ # Bind name to non-global scopes, but as already "used".
705+ node_value .used = (global_scope , node )
706+ for scope in self .scopeStack [global_scope_index + 1 :]:
707+ scope [node_name ] = node_value
665708
666709 NONLOCAL = GLOBAL
667710
@@ -670,6 +713,8 @@ def GENERATOREXP(self, node):
670713 self .handleChildren (node )
671714 self .popScope ()
672715
716+ LISTCOMP = handleChildren if PY2 else GENERATOREXP
717+
673718 DICTCOMP = SETCOMP = GENERATOREXP
674719
675720 def NAME (self , node ):
@@ -693,6 +738,10 @@ def NAME(self, node):
693738 raise RuntimeError ("Got impossible expression context: %r" % (node .ctx ,))
694739
695740 def RETURN (self , node ):
741+ if isinstance (self .scope , ClassScope ):
742+ self .report (messages .ReturnOutsideFunction , node )
743+ return
744+
696745 if (
697746 node .value and
698747 hasattr (self .scope , 'returnValue' ) and
@@ -705,7 +754,7 @@ def YIELD(self, node):
705754 self .scope .isGenerator = True
706755 self .handleNode (node .value , node )
707756
708- YIELDFROM = YIELD
757+ AWAIT = YIELDFROM = YIELD
709758
710759 def FUNCTIONDEF (self , node ):
711760 for deco in node .decorator_list :
@@ -715,6 +764,8 @@ def FUNCTIONDEF(self, node):
715764 if self .withDoctest :
716765 self .deferFunction (lambda : self .handleDoctests (node ))
717766
767+ ASYNCFUNCTIONDEF = FUNCTIONDEF
768+
718769 def LAMBDA (self , node ):
719770 args = []
720771 annotations = []
0 commit comments