diff --git a/packages/babel-traverse/src/scope/lib/renamer.js b/packages/babel-traverse/src/scope/lib/renamer.js index cdfd90819681..89dee46e76c1 100644 --- a/packages/babel-traverse/src/scope/lib/renamer.js +++ b/packages/babel-traverse/src/scope/lib/renamer.js @@ -29,6 +29,24 @@ const renameVisitor = { }, }; +function isSafeBinding(scope, node) { + if (!scope.hasOwnBinding(node.name)) return true; + const { kind } = scope.getOwnBinding(node.name); + return kind === "param" || kind === "local"; +} + +const outerBindingVisitor = { + ReferencedIdentifier(path, state) { + const { node } = path; + if (node.name === state.oldName && !isSafeBinding(state.scope, node)) { + state.paramDefaultOuterBinding = true; + path.stop(); + } + }, + Scope(path) { + path.skip(); + }, +}; export default class Renamer { constructor(binding: Binding, oldName: string, newName: string) { this.newName = newName; @@ -116,7 +134,37 @@ export default class Renamer { } } - scope.traverse(block || scope.block, renameVisitor, this); + const state = { + paramDefaultOuterBinding: false, + scope, + oldName, + }; + if (scope.path.isFunction()) { + const params = scope.path.get("params"); + for (let i = 0; i < params.length; i++) { + const param = params[i]; + if (param.isAssignmentPattern()) { + const right = param.get("right"); + if (!state.paramDefaultOuterBinding) { + if ( + right.isIdentifier() && + right.node.body.name === oldName && + !isSafeBinding(scope, right.node.body) + ) { + state.paramDefaultOuterBinding = true; + break; + } else { + right.traverse(outerBindingVisitor, state); + } + } + } + } + } + if (state.paramDefaultOuterBinding) { + scope.traverse(block || scope.block.body, renameVisitor, this); + } else { + scope.traverse(block || scope.block, renameVisitor, this); + } if (!block) { scope.removeOwnBinding(oldName);