--- /dev/null
+"""Fixer for it.next() -> next(it), per PEP 3114."""\r
+# Author: Collin Winter\r
+\r
+# Things that currently aren't covered:\r
+# - listcomp "next" names aren't warned\r
+# - "with" statement targets aren't checked\r
+\r
+# Local imports\r
+from ..pgen2 import token\r
+from ..pygram import python_symbols as syms\r
+from .. import fixer_base\r
+from ..fixer_util import Name, Call, find_binding\r
+\r
+bind_warning = "Calls to builtin next() possibly shadowed by global binding"\r
+\r
+\r
+class FixNext(fixer_base.BaseFix):\r
+ BM_compatible = True\r
+ PATTERN = """\r
+ power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > >\r
+ |\r
+ power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > >\r
+ |\r
+ classdef< 'class' any+ ':'\r
+ suite< any*\r
+ funcdef< 'def'\r
+ name='next'\r
+ parameters< '(' NAME ')' > any+ >\r
+ any* > >\r
+ |\r
+ global=global_stmt< 'global' any* 'next' any* >\r
+ """\r
+\r
+ order = "pre" # Pre-order tree traversal\r
+\r
+ def start_tree(self, tree, filename):\r
+ super(FixNext, self).start_tree(tree, filename)\r
+\r
+ n = find_binding(u'next', tree)\r
+ if n:\r
+ self.warning(n, bind_warning)\r
+ self.shadowed_next = True\r
+ else:\r
+ self.shadowed_next = False\r
+\r
+ def transform(self, node, results):\r
+ assert results\r
+\r
+ base = results.get("base")\r
+ attr = results.get("attr")\r
+ name = results.get("name")\r
+\r
+ if base:\r
+ if self.shadowed_next:\r
+ attr.replace(Name(u"__next__", prefix=attr.prefix))\r
+ else:\r
+ base = [n.clone() for n in base]\r
+ base[0].prefix = u""\r
+ node.replace(Call(Name(u"next", prefix=node.prefix), base))\r
+ elif name:\r
+ n = Name(u"__next__", prefix=name.prefix)\r
+ name.replace(n)\r
+ elif attr:\r
+ # We don't do this transformation if we're assigning to "x.next".\r
+ # Unfortunately, it doesn't seem possible to do this in PATTERN,\r
+ # so it's being done here.\r
+ if is_assign_target(node):\r
+ head = results["head"]\r
+ if "".join([str(n) for n in head]).strip() == u'__builtin__':\r
+ self.warning(node, bind_warning)\r
+ return\r
+ attr.replace(Name(u"__next__"))\r
+ elif "global" in results:\r
+ self.warning(node, bind_warning)\r
+ self.shadowed_next = True\r
+\r
+\r
+### The following functions help test if node is part of an assignment\r
+### target.\r
+\r
+def is_assign_target(node):\r
+ assign = find_assign(node)\r
+ if assign is None:\r
+ return False\r
+\r
+ for child in assign.children:\r
+ if child.type == token.EQUAL:\r
+ return False\r
+ elif is_subtree(child, node):\r
+ return True\r
+ return False\r
+\r
+def find_assign(node):\r
+ if node.type == syms.expr_stmt:\r
+ return node\r
+ if node.type == syms.simple_stmt or node.parent is None:\r
+ return None\r
+ return find_assign(node.parent)\r
+\r
+def is_subtree(root, node):\r
+ if root == node:\r
+ return True\r
+ return any(is_subtree(c, node) for c in root.children)\r