blob: 66a00c27b651d6209fda00b180f5094270d9de76 [file] [log] [blame]
Martin v. Löwisef04c442008-03-19 05:04:44 +00001"""Fixer for it.next() -> next(it), per PEP 3114."""
2# Author: Collin Winter
3
4# Things that currently aren't covered:
5# - listcomp "next" names aren't warned
6# - "with" statement targets aren't checked
7
8# Local imports
9from ..pgen2 import token
10from ..pygram import python_symbols as syms
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +000011from .. import fixer_base
Benjamin Peterson5cff9312008-11-28 23:01:28 +000012from ..fixer_util import Name, Call, find_binding
Martin v. Löwisef04c442008-03-19 05:04:44 +000013
14bind_warning = "Calls to builtin next() possibly shadowed by global binding"
15
16
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +000017class FixNext(fixer_base.BaseFix):
Martin v. Löwisef04c442008-03-19 05:04:44 +000018 PATTERN = """
19 power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > >
20 |
21 power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > >
22 |
23 classdef< 'class' any+ ':'
24 suite< any*
25 funcdef< 'def'
26 name='next'
27 parameters< '(' NAME ')' > any+ >
28 any* > >
29 |
30 global=global_stmt< 'global' any* 'next' any* >
Martin v. Löwisef04c442008-03-19 05:04:44 +000031 """
32
33 order = "pre" # Pre-order tree traversal
34
35 def start_tree(self, tree, filename):
36 super(FixNext, self).start_tree(tree, filename)
Benjamin Peterson206e3072008-10-19 14:07:49 +000037
38 n = find_binding('next', tree)
39 if n:
40 self.warning(n, bind_warning)
41 self.shadowed_next = True
42 else:
43 self.shadowed_next = False
Martin v. Löwisef04c442008-03-19 05:04:44 +000044
45 def transform(self, node, results):
46 assert results
47
48 base = results.get("base")
49 attr = results.get("attr")
50 name = results.get("name")
Martin v. Löwisef04c442008-03-19 05:04:44 +000051
52 if base:
Martin v. Löwisf733c602008-03-19 05:26:18 +000053 if self.shadowed_next:
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000054 attr.replace(Name("__next__", prefix=attr.prefix))
Martin v. Löwisf733c602008-03-19 05:26:18 +000055 else:
56 base = [n.clone() for n in base]
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000057 base[0].prefix = ""
58 node.replace(Call(Name("next", prefix=node.prefix), base))
Martin v. Löwisef04c442008-03-19 05:04:44 +000059 elif name:
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000060 n = Name("__next__", prefix=name.prefix)
Martin v. Löwisef04c442008-03-19 05:04:44 +000061 name.replace(n)
62 elif attr:
63 # We don't do this transformation if we're assigning to "x.next".
64 # Unfortunately, it doesn't seem possible to do this in PATTERN,
65 # so it's being done here.
66 if is_assign_target(node):
67 head = results["head"]
68 if "".join([str(n) for n in head]).strip() == '__builtin__':
69 self.warning(node, bind_warning)
70 return
71 attr.replace(Name("__next__"))
72 elif "global" in results:
73 self.warning(node, bind_warning)
74 self.shadowed_next = True
Martin v. Löwisef04c442008-03-19 05:04:44 +000075
76
77### The following functions help test if node is part of an assignment
78### target.
79
80def is_assign_target(node):
81 assign = find_assign(node)
82 if assign is None:
83 return False
84
85 for child in assign.children:
86 if child.type == token.EQUAL:
87 return False
88 elif is_subtree(child, node):
89 return True
90 return False
91
92def find_assign(node):
93 if node.type == syms.expr_stmt:
94 return node
95 if node.type == syms.simple_stmt or node.parent is None:
96 return None
97 return find_assign(node.parent)
98
99def is_subtree(root, node):
100 if root == node:
101 return True
Benjamin Peterson20211002009-11-25 18:34:42 +0000102 return any(is_subtree(c, node) for c in root.children)