17db96d56Sopenharmony_ci"""Fixer for it.next() -> next(it), per PEP 3114.""" 27db96d56Sopenharmony_ci# Author: Collin Winter 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ci# Things that currently aren't covered: 57db96d56Sopenharmony_ci# - listcomp "next" names aren't warned 67db96d56Sopenharmony_ci# - "with" statement targets aren't checked 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ci# Local imports 97db96d56Sopenharmony_cifrom ..pgen2 import token 107db96d56Sopenharmony_cifrom ..pygram import python_symbols as syms 117db96d56Sopenharmony_cifrom .. import fixer_base 127db96d56Sopenharmony_cifrom ..fixer_util import Name, Call, find_binding 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_cibind_warning = "Calls to builtin next() possibly shadowed by global binding" 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciclass FixNext(fixer_base.BaseFix): 187db96d56Sopenharmony_ci BM_compatible = True 197db96d56Sopenharmony_ci PATTERN = """ 207db96d56Sopenharmony_ci power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > > 217db96d56Sopenharmony_ci | 227db96d56Sopenharmony_ci power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > > 237db96d56Sopenharmony_ci | 247db96d56Sopenharmony_ci classdef< 'class' any+ ':' 257db96d56Sopenharmony_ci suite< any* 267db96d56Sopenharmony_ci funcdef< 'def' 277db96d56Sopenharmony_ci name='next' 287db96d56Sopenharmony_ci parameters< '(' NAME ')' > any+ > 297db96d56Sopenharmony_ci any* > > 307db96d56Sopenharmony_ci | 317db96d56Sopenharmony_ci global=global_stmt< 'global' any* 'next' any* > 327db96d56Sopenharmony_ci """ 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci order = "pre" # Pre-order tree traversal 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ci def start_tree(self, tree, filename): 377db96d56Sopenharmony_ci super(FixNext, self).start_tree(tree, filename) 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci n = find_binding('next', tree) 407db96d56Sopenharmony_ci if n: 417db96d56Sopenharmony_ci self.warning(n, bind_warning) 427db96d56Sopenharmony_ci self.shadowed_next = True 437db96d56Sopenharmony_ci else: 447db96d56Sopenharmony_ci self.shadowed_next = False 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci def transform(self, node, results): 477db96d56Sopenharmony_ci assert results 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci base = results.get("base") 507db96d56Sopenharmony_ci attr = results.get("attr") 517db96d56Sopenharmony_ci name = results.get("name") 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_ci if base: 547db96d56Sopenharmony_ci if self.shadowed_next: 557db96d56Sopenharmony_ci attr.replace(Name("__next__", prefix=attr.prefix)) 567db96d56Sopenharmony_ci else: 577db96d56Sopenharmony_ci base = [n.clone() for n in base] 587db96d56Sopenharmony_ci base[0].prefix = "" 597db96d56Sopenharmony_ci node.replace(Call(Name("next", prefix=node.prefix), base)) 607db96d56Sopenharmony_ci elif name: 617db96d56Sopenharmony_ci n = Name("__next__", prefix=name.prefix) 627db96d56Sopenharmony_ci name.replace(n) 637db96d56Sopenharmony_ci elif attr: 647db96d56Sopenharmony_ci # We don't do this transformation if we're assigning to "x.next". 657db96d56Sopenharmony_ci # Unfortunately, it doesn't seem possible to do this in PATTERN, 667db96d56Sopenharmony_ci # so it's being done here. 677db96d56Sopenharmony_ci if is_assign_target(node): 687db96d56Sopenharmony_ci head = results["head"] 697db96d56Sopenharmony_ci if "".join([str(n) for n in head]).strip() == '__builtin__': 707db96d56Sopenharmony_ci self.warning(node, bind_warning) 717db96d56Sopenharmony_ci return 727db96d56Sopenharmony_ci attr.replace(Name("__next__")) 737db96d56Sopenharmony_ci elif "global" in results: 747db96d56Sopenharmony_ci self.warning(node, bind_warning) 757db96d56Sopenharmony_ci self.shadowed_next = True 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci### The following functions help test if node is part of an assignment 797db96d56Sopenharmony_ci### target. 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_cidef is_assign_target(node): 827db96d56Sopenharmony_ci assign = find_assign(node) 837db96d56Sopenharmony_ci if assign is None: 847db96d56Sopenharmony_ci return False 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci for child in assign.children: 877db96d56Sopenharmony_ci if child.type == token.EQUAL: 887db96d56Sopenharmony_ci return False 897db96d56Sopenharmony_ci elif is_subtree(child, node): 907db96d56Sopenharmony_ci return True 917db96d56Sopenharmony_ci return False 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_cidef find_assign(node): 947db96d56Sopenharmony_ci if node.type == syms.expr_stmt: 957db96d56Sopenharmony_ci return node 967db96d56Sopenharmony_ci if node.type == syms.simple_stmt or node.parent is None: 977db96d56Sopenharmony_ci return None 987db96d56Sopenharmony_ci return find_assign(node.parent) 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_cidef is_subtree(root, node): 1017db96d56Sopenharmony_ci if root == node: 1027db96d56Sopenharmony_ci return True 1037db96d56Sopenharmony_ci return any(is_subtree(c, node) for c in root.children) 104