453 node, value.name, existing.source) |
453 node, value.name, existing.source) |
454 |
454 |
455 elif isinstance(existing, Importation) and value.redefines(existing): |
455 elif isinstance(existing, Importation) and value.redefines(existing): |
456 existing.redefined.append(node) |
456 existing.redefined.append(node) |
457 |
457 |
|
458 if value.name in self.scope: |
|
459 # then assume the rebound name is used as a global or within a loop |
|
460 value.used = self.scope[value.name].used |
|
461 |
458 self.scope[value.name] = value |
462 self.scope[value.name] = value |
459 |
463 |
460 def getNodeHandler(self, node_class): |
464 def getNodeHandler(self, node_class): |
461 try: |
465 try: |
462 return self._nodeHandlers[node_class] |
466 return self._nodeHandlers[node_class] |
476 pass |
480 pass |
477 else: |
481 else: |
478 return |
482 return |
479 |
483 |
480 scopes = [scope for scope in self.scopeStack[:-1] |
484 scopes = [scope for scope in self.scopeStack[:-1] |
481 if isinstance(scope, (FunctionScope, ModuleScope))] |
485 if isinstance(scope, (FunctionScope, ModuleScope, GeneratorScope))] |
482 if isinstance(self.scope, GeneratorScope) and scopes[-1] != self.scopeStack[-2]: |
486 if isinstance(self.scope, GeneratorScope) and scopes[-1] != self.scopeStack[-2]: |
483 scopes.append(self.scopeStack[-2]) |
487 scopes.append(self.scopeStack[-2]) |
484 |
488 |
485 # try enclosing function scopes and global scope |
489 # try enclosing function scopes and global scope |
486 importStarred = self.scope.importStarred |
490 importStarred = self.scope.importStarred |
531 binding = Binding(name, node) |
535 binding = Binding(name, node) |
532 elif name == '__all__' and isinstance(self.scope, ModuleScope): |
536 elif name == '__all__' and isinstance(self.scope, ModuleScope): |
533 binding = ExportBinding(name, node.parent, self.scope) |
537 binding = ExportBinding(name, node.parent, self.scope) |
534 else: |
538 else: |
535 binding = Assignment(name, node) |
539 binding = Assignment(name, node) |
536 if name in self.scope: |
|
537 binding.used = self.scope[name].used |
|
538 self.addBinding(node, binding) |
540 self.addBinding(node, binding) |
539 |
541 |
540 def handleNodeDelete(self, node): |
542 def handleNodeDelete(self, node): |
|
543 |
|
544 def on_conditional_branch(): |
|
545 """ |
|
546 Return `True` if node is part of a conditional body. |
|
547 """ |
|
548 current = getattr(node, 'parent', None) |
|
549 while current: |
|
550 if isinstance(current, (ast.If, ast.While, ast.IfExp)): |
|
551 return True |
|
552 current = getattr(current, 'parent', None) |
|
553 return False |
|
554 |
541 name = getNodeName(node) |
555 name = getNodeName(node) |
542 if not name: |
556 if not name: |
543 return |
557 return |
|
558 |
|
559 if on_conditional_branch(): |
|
560 # We can not predict if this conditional branch is going to |
|
561 # be executed. |
|
562 return |
|
563 |
544 if isinstance(self.scope, FunctionScope) and name in self.scope.globals: |
564 if isinstance(self.scope, FunctionScope) and name in self.scope.globals: |
545 self.scope.globals.remove(name) |
565 self.scope.globals.remove(name) |
546 else: |
566 else: |
547 try: |
567 try: |
548 del self.scope[name] |
568 del self.scope[name] |
636 def ignore(self, node): |
656 def ignore(self, node): |
637 pass |
657 pass |
638 |
658 |
639 # "stmt" type nodes |
659 # "stmt" type nodes |
640 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \ |
660 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \ |
641 ASYNCWITH = RAISE = TRYFINALLY = ASSERT = EXEC = EXPR = \ |
661 ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = ASSERT = EXEC = \ |
642 ASSIGN = handleChildren |
662 EXPR = ASSIGN = handleChildren |
643 |
663 |
644 CONTINUE = BREAK = PASS = ignore |
664 CONTINUE = BREAK = PASS = ignore |
645 |
665 |
646 # "expr" type nodes |
666 # "expr" type nodes |
647 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = \ |
667 BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = \ |
660 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \ |
680 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \ |
661 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \ |
681 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \ |
662 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore |
682 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore |
663 |
683 |
664 # additional node types |
684 # additional node types |
665 LISTCOMP = COMPREHENSION = KEYWORD = handleChildren |
685 COMPREHENSION = KEYWORD = handleChildren |
666 |
686 |
667 def GLOBAL(self, node): |
687 def GLOBAL(self, node): |
668 """ |
688 """ |
669 Keep track of globals declarations. |
689 Keep track of globals declarations. |
670 """ |
690 """ |
671 if isinstance(self.scope, FunctionScope): |
691 # In doctests, the global scope is an anonymous function at index 1. |
672 self.scope.globals.update(node.names) |
692 global_scope_index = 0#1 if self.withDoctest else 0 |
|
693 global_scope = self.scopeStack[global_scope_index] |
|
694 |
|
695 # Ignore 'global' statement in global scope. |
|
696 if self.scope is not global_scope: |
|
697 |
|
698 # One 'global' statement can bind multiple (comma-delimited) names. |
|
699 for node_name in node.names: |
|
700 node_value = Assignment(node_name, node) |
|
701 |
|
702 # Remove UndefinedName messages already reported for this name. |
|
703 self.messages = [ |
|
704 m for m in self.messages if not |
|
705 isinstance(m, messages.UndefinedName) and not |
|
706 m.message_args[0] == node_name] |
|
707 |
|
708 # Bind name to global scope if it doesn't exist already. |
|
709 global_scope.setdefault(node_name, node_value) |
|
710 |
|
711 # Bind name to non-global scopes, but as already "used". |
|
712 node_value.used = (global_scope, node) |
|
713 for scope in self.scopeStack[global_scope_index + 1:]: |
|
714 scope[node_name] = node_value |
|
715 if isinstance(scope, FunctionScope): |
|
716 scope.globals.add(node_name) |
673 |
717 |
674 NONLOCAL = GLOBAL |
718 NONLOCAL = GLOBAL |
675 |
719 |
676 def GENERATOREXP(self, node): |
720 def GENERATOREXP(self, node): |
677 self.pushScope(GeneratorScope) |
721 self.pushScope(GeneratorScope) |
678 self.handleChildren(node) |
722 self.handleChildren(node) |
679 self.popScope() |
723 self.popScope() |
|
724 |
|
725 LISTCOMP = handleChildren if PY2 else GENERATOREXP |
680 |
726 |
681 DICTCOMP = SETCOMP = GENERATOREXP |
727 DICTCOMP = SETCOMP = GENERATOREXP |
682 |
728 |
683 def NAME(self, node): |
729 def NAME(self, node): |
684 """ |
730 """ |
699 # must be a Param context -- this only happens for names in function |
745 # must be a Param context -- this only happens for names in function |
700 # arguments, but these aren't dispatched through here |
746 # arguments, but these aren't dispatched through here |
701 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) |
747 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) |
702 |
748 |
703 def RETURN(self, node): |
749 def RETURN(self, node): |
|
750 if isinstance(self.scope, ClassScope): |
|
751 self.report(messages.ReturnOutsideFunction, node) |
|
752 return |
|
753 |
704 if ( |
754 if ( |
705 node.value and |
755 node.value and |
706 hasattr(self.scope, 'returnValue') and |
756 hasattr(self.scope, 'returnValue') and |
707 not self.scope.returnValue |
757 not self.scope.returnValue |
708 ): |
758 ): |
711 |
761 |
712 def YIELD(self, node): |
762 def YIELD(self, node): |
713 self.scope.isGenerator = True |
763 self.scope.isGenerator = True |
714 self.handleNode(node.value, node) |
764 self.handleNode(node.value, node) |
715 |
765 |
716 YIELDFROM = YIELD |
766 AWAIT = YIELDFROM = YIELD |
717 |
767 |
718 def FUNCTIONDEF(self, node): |
768 def FUNCTIONDEF(self, node): |
719 for deco in node.decorator_list: |
769 for deco in node.decorator_list: |
720 self.handleNode(deco, node) |
770 self.handleNode(deco, node) |
721 self.LAMBDA(node) |
771 self.LAMBDA(node) |