From 80b4d843468b982423daadf3e096bbf87ab635f1 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 9 Aug 2021 00:41:10 +0800 Subject: [PATCH 1/5] fix: fix static private field shadowed by local variable currently throw an error, maybe we could generate correct code fix #12960 --- .../src/fields.ts | 21 +++++++++++++------ .../src/index.ts | 4 +++- .../fixtures/private/static-shadow/input.js | 9 ++++++++ .../private/static-shadow/options.json | 4 ++++ 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index 695979cdd11f..fbf8d129ea65 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -58,7 +58,7 @@ export function buildPrivateNamesMap(props: PropPath[]) { export function buildPrivateNamesNodes( privateNamesMap: PrivateNamesMap, privateFieldsAsProperties: boolean, - state, + state: File, ) { const initNodes: t.Statement[] = []; @@ -165,6 +165,7 @@ interface PrivateNameState { classRef: t.Identifier; file: File; noDocumentAll: boolean; + innerBinding?: t.Identifier; } const privateNameVisitor = privateNameVisitorFactory< @@ -255,7 +256,7 @@ const privateNameHandlerSpec: Handler & Receiver = }, get(member) { - const { classRef, privateNamesMap, file } = this; + const { classRef, privateNamesMap, file, innerBinding } = this; const { name } = (member.node.property as t.PrivateName).id; const { id, @@ -273,6 +274,13 @@ const privateNameHandlerSpec: Handler & Receiver = ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet"; + const binding = member.scope.getBinding(classRef.name); + if (innerBinding && binding && !(binding.identifier === innerBinding)) { + // the classRef has been shadowed + throw binding.path.buildCodeFrameError( + `Shadowing class ${classRef.name} with private property`, + ); + } return t.callExpression(file.addHelper(helperName), [ this.receiver(member), t.cloneNode(classRef), @@ -463,8 +471,8 @@ export function transformPrivateNamesUsage( ref: t.Identifier, path: NodePath, privateNamesMap: PrivateNamesMap, - { privateFieldsAsProperties, noDocumentAll }, - state, + { privateFieldsAsProperties, noDocumentAll, innerBinding }, + state: File, ) { if (!privateNamesMap.size) return; @@ -479,6 +487,7 @@ export function transformPrivateNamesUsage( file: state, ...handler, noDocumentAll, + innerBinding, }); body.traverse(privateInVisitor, { privateNamesMap, @@ -770,7 +779,7 @@ const thisContextVisitor = traverse.visitors.merge([ ]); const innerReferencesVisitor = { - ReferencedIdentifier(path, state) { + ReferencedIdentifier(path: NodePath, state) { if ( path.scope.bindingIdentifierEquals(path.node.name, state.innerBinding) ) { @@ -831,7 +840,7 @@ export function buildFieldsInitNodes( superRef: t.Expression | undefined, props: PropPath[], privateNamesMap: PrivateNamesMap, - state, + state: File, setPublicClassFields: boolean, privateFieldsAsProperties: boolean, constantSuper: boolean, diff --git a/packages/babel-helper-create-class-features-plugin/src/index.ts b/packages/babel-helper-create-class-features-plugin/src/index.ts index 24546834a122..57c7595a158d 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.ts +++ b/packages/babel-helper-create-class-features-plugin/src/index.ts @@ -1,4 +1,5 @@ import { types as t } from "@babel/core"; +import type { File } from "@babel/core"; import type { NodePath } from "@babel/traverse"; import nameFunction from "@babel/helper-function-name"; import splitExportDeclaration from "@babel/helper-split-export-declaration"; @@ -92,7 +93,7 @@ export function createClassFeaturePlugin({ }, visitor: { - Class(path: NodePath, state) { + Class(path: NodePath, state: File) { if (this.file.get(versionKey) !== version) return; verifyUsedFeatures(path, this.file); @@ -198,6 +199,7 @@ export function createClassFeaturePlugin({ { privateFieldsAsProperties: privateFieldsAsProperties ?? loose, noDocumentAll, + innerBinding, }, state, ); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js new file mode 100644 index 000000000000..1c58dc807cf1 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js @@ -0,0 +1,9 @@ +class Test { + + static #x = 1 + + method() { + const Test = 1; + return this.#x; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json new file mode 100644 index 000000000000..b691a333b287 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["proposal-class-properties"], + "throws": "Shadowing class Test with private property" +} From d01e651b83b679b1a81ca04431f4c8cf3ad820f1 Mon Sep 17 00:00:00 2001 From: Colin Wang Date: Tue, 10 Aug 2021 21:58:04 +0800 Subject: [PATCH 2/5] feat: rename local variable and add test cases --- .../src/fields.ts | 14 +++++++++----- .../private-loose/static-shadow/exec.js | 15 +++++++++++++++ .../private-loose/static-shadow/input.js | 13 +++++++++++++ .../private-loose/static-shadow/options.json | 3 +++ .../private-loose/static-shadow/output.js | 18 ++++++++++++++++++ .../fixtures/private/static-shadow/exec.js | 15 +++++++++++++++ .../fixtures/private/static-shadow/input.js | 10 +++++++--- .../private/static-shadow/options.json | 3 +-- .../fixtures/private/static-shadow/output.js | 18 ++++++++++++++++++ 9 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index fbf8d129ea65..cb9c8f54341b 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -275,11 +275,15 @@ const privateNameHandlerSpec: Handler & Receiver = : "classStaticPrivateFieldSpecGet"; const binding = member.scope.getBinding(classRef.name); - if (innerBinding && binding && !(binding.identifier === innerBinding)) { - // the classRef has been shadowed - throw binding.path.buildCodeFrameError( - `Shadowing class ${classRef.name} with private property`, - ); + if (innerBinding && binding && innerBinding !== binding.identifier) { + // the classRef has been shadowed, rename the local variable + let local = binding.path; + while ( + !local.scope.bindingIdentifierEquals(classRef.name, innerBinding) + ) { + local.scope.rename(classRef.name); + local = local.parentPath; + } } return t.callExpression(file.addHelper(helperName), [ this.receiver(member), diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js new file mode 100644 index 000000000000..cf66e02ddcf6 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js @@ -0,0 +1,15 @@ +class Test { + + static #x = 1 + + static method() { + const Test = 2; + const func = () => { + const Test = 3; + return this.#x; + } + return func(); + } +} + +expect(Test.method()).toBe(1) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js new file mode 100644 index 000000000000..20d94408b73b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js @@ -0,0 +1,13 @@ +class Test { + + static #x = 1 + + static method() { + const Test = 2; + const func = () => { + const Test = 3; + return this.#x; + } + return func(); + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/options.json new file mode 100644 index 000000000000..19ed5174f545 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js new file mode 100644 index 000000000000..4e85e4b2686a --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js @@ -0,0 +1,18 @@ +class Test { + static method() { + const _Test2 = 2; + + const func = () => { + const _Test = 3; + return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x); + }; + + return func(); + } + +} + +var _x = { + writable: true, + value: 1 +}; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js new file mode 100644 index 000000000000..cf66e02ddcf6 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js @@ -0,0 +1,15 @@ +class Test { + + static #x = 1 + + static method() { + const Test = 2; + const func = () => { + const Test = 3; + return this.#x; + } + return func(); + } +} + +expect(Test.method()).toBe(1) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js index 1c58dc807cf1..20d94408b73b 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js @@ -2,8 +2,12 @@ class Test { static #x = 1 - method() { - const Test = 1; - return this.#x; + static method() { + const Test = 2; + const func = () => { + const Test = 3; + return this.#x; + } + return func(); } } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json index b691a333b287..19ed5174f545 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/options.json @@ -1,4 +1,3 @@ { - "plugins": ["proposal-class-properties"], - "throws": "Shadowing class Test with private property" + "plugins": ["proposal-class-properties"] } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js new file mode 100644 index 000000000000..4e85e4b2686a --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js @@ -0,0 +1,18 @@ +class Test { + static method() { + const _Test2 = 2; + + const func = () => { + const _Test = 3; + return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x); + }; + + return func(); + } + +} + +var _x = { + writable: true, + value: 1 +}; From 8de2f463c4401067ce335a8db7272bd723b9e4de Mon Sep 17 00:00:00 2001 From: Colin Wang Date: Tue, 10 Aug 2021 22:55:34 +0800 Subject: [PATCH 3/5] feat: add unshadow to privateIn visitor also add test cases --- .../src/fields.ts | 39 +++++++++++++------ .../private-loose/static-shadow/exec.js | 17 ++++++++ .../private-loose/static-shadow/input.js | 13 +++++++ .../private-loose/static-shadow/options.json | 3 ++ .../private-loose/static-shadow/output.js | 18 +++++++++ .../fixtures/private/static-shadow/exec.js | 17 ++++++++ .../fixtures/private/static-shadow/input.js | 13 +++++++ .../private/static-shadow/options.json | 3 ++ .../fixtures/private/static-shadow/output.js | 18 +++++++++ .../to-native-fields/static-shadow/exec.js | 17 ++++++++ .../to-native-fields/static-shadow/input.js | 13 +++++++ .../static-shadow/options.json | 3 ++ .../to-native-fields/static-shadow/output.js | 18 +++++++++ 13 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/options.json create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/options.json create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/options.json create mode 100644 packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index cb9c8f54341b..cd4f5a48e086 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -1,6 +1,6 @@ import { template, traverse, types as t } from "@babel/core"; import type { File } from "@babel/core"; -import type { NodePath, Visitor } from "@babel/traverse"; +import type { NodePath, Visitor, Scope } from "@babel/traverse"; import ReplaceSupers, { environmentVisitor, } from "@babel/helper-replace-supers"; @@ -189,9 +189,26 @@ const privateNameVisitor = privateNameVisitorFactory< }, }); +// rename all bindings that shadows innerBinding +function unshadow( + name: string, + scope: Scope, + innerBinding: t.Identifier | undefined, +) { + const binding = scope.getBinding(name); + if (innerBinding && binding && innerBinding !== binding.identifier) { + // the classRef has been shadowed, rename the local variable + while (!scope.bindingIdentifierEquals(name, innerBinding)) { + scope.rename(name); + scope = scope.parent; + } + } +} + const privateInVisitor = privateNameVisitorFactory<{ classRef: t.Identifier; file: File; + innerBinding?: t.Identifier; }>({ BinaryExpression(path) { const { operator, left, right } = path.node; @@ -205,6 +222,10 @@ const privateInVisitor = privateNameVisitorFactory<{ if (!privateNamesMap.has(name)) return; if (redeclared && redeclared.includes(name)) return; + // if there are any local variable shadowing classRef, unshadow it + // see #12960 + unshadow(this.classRef.name, path.scope, this.innerBinding); + if (privateFieldsAsProperties) { const { id } = privateNamesMap.get(name); path.replaceWith(template.expression.ast` @@ -274,17 +295,10 @@ const privateNameHandlerSpec: Handler & Receiver = ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet"; - const binding = member.scope.getBinding(classRef.name); - if (innerBinding && binding && innerBinding !== binding.identifier) { - // the classRef has been shadowed, rename the local variable - let local = binding.path; - while ( - !local.scope.bindingIdentifierEquals(classRef.name, innerBinding) - ) { - local.scope.rename(classRef.name); - local = local.parentPath; - } - } + // if there are any local variable shadowing classRef, unshadow it + // see #12960 + unshadow(classRef.name, member.scope, innerBinding); + return t.callExpression(file.addHelper(helperName), [ this.receiver(member), t.cloneNode(classRef), @@ -498,6 +512,7 @@ export function transformPrivateNamesUsage( classRef: ref, file: state, privateFieldsAsProperties, + innerBinding, }); } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js new file mode 100644 index 000000000000..4ecedebe4259 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js @@ -0,0 +1,17 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} + +const t = new Test(); +const t2 = new Test(); +expect(t.method(Test)).toBe(true) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js new file mode 100644 index 000000000000..343920f28e57 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js @@ -0,0 +1,13 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/options.json new file mode 100644 index 000000000000..19ed5174f545 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js new file mode 100644 index 000000000000..64137a77f39d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js @@ -0,0 +1,18 @@ +class Test { + method(other) { + const _Test2 = 2; + + const func = () => { + const _Test = 3; + return other === Test; + }; + + return func(); + } + +} + +var _x = { + writable: true, + value: 1 +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js new file mode 100644 index 000000000000..4ecedebe4259 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js @@ -0,0 +1,17 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} + +const t = new Test(); +const t2 = new Test(); +expect(t.method(Test)).toBe(true) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js new file mode 100644 index 000000000000..343920f28e57 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js @@ -0,0 +1,13 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/options.json new file mode 100644 index 000000000000..19ed5174f545 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js new file mode 100644 index 000000000000..64137a77f39d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js @@ -0,0 +1,18 @@ +class Test { + method(other) { + const _Test2 = 2; + + const func = () => { + const _Test = 3; + return other === Test; + }; + + return func(); + } + +} + +var _x = { + writable: true, + value: 1 +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js new file mode 100644 index 000000000000..4ecedebe4259 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js @@ -0,0 +1,17 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} + +const t = new Test(); +const t2 = new Test(); +expect(t.method(Test)).toBe(true) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js new file mode 100644 index 000000000000..343920f28e57 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js @@ -0,0 +1,13 @@ +class Test { + + static #x = 1 + + method(other) { + const Test = 2; + const func = () => { + const Test = 3; + return #x in other; + } + return func(); + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/options.json new file mode 100644 index 000000000000..19ed5174f545 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js new file mode 100644 index 000000000000..64137a77f39d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js @@ -0,0 +1,18 @@ +class Test { + method(other) { + const _Test2 = 2; + + const func = () => { + const _Test = 3; + return other === Test; + }; + + return func(); + } + +} + +var _x = { + writable: true, + value: 1 +}; From 5c366b307688372b2c1b182939e569d08be1b46f Mon Sep 17 00:00:00 2001 From: Colin Wang Date: Wed, 11 Aug 2021 13:04:37 +0800 Subject: [PATCH 4/5] test: add reference to shadowed variable --- .../test/fixtures/private-loose/static-shadow/exec.js | 6 +++--- .../test/fixtures/private-loose/static-shadow/input.js | 4 ++-- .../test/fixtures/private-loose/static-shadow/output.js | 4 ++-- .../test/fixtures/private/static-shadow/exec.js | 6 +++--- .../test/fixtures/private/static-shadow/input.js | 4 ++-- .../test/fixtures/private/static-shadow/output.js | 4 ++-- .../test/fixtures/private-loose/static-shadow/exec.js | 6 +++--- .../test/fixtures/private-loose/static-shadow/input.js | 4 ++-- .../test/fixtures/private-loose/static-shadow/output.js | 4 ++-- .../test/fixtures/private/static-shadow/exec.js | 6 +++--- .../test/fixtures/private/static-shadow/input.js | 4 ++-- .../test/fixtures/private/static-shadow/output.js | 4 ++-- .../test/fixtures/to-native-fields/static-shadow/exec.js | 6 +++--- .../test/fixtures/to-native-fields/static-shadow/input.js | 4 ++-- .../test/fixtures/to-native-fields/static-shadow/output.js | 4 ++-- 15 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js index cf66e02ddcf6..101547f13cee 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/exec.js @@ -6,10 +6,10 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return this.#x; + return this.#x + Test; } - return func(); + return func() + Test; } } -expect(Test.method()).toBe(1) +expect(Test.method()).toBe(6) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js index 20d94408b73b..5f5ffa0b2343 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/input.js @@ -6,8 +6,8 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return this.#x; + return this.#x + Test; } - return func(); + return func() + Test; } } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js index 4e85e4b2686a..8b03caa83f92 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/static-shadow/output.js @@ -4,10 +4,10 @@ class Test { const func = () => { const _Test = 3; - return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x); + return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x) + _Test; }; - return func(); + return func() + _Test2; } } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js index cf66e02ddcf6..101547f13cee 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/exec.js @@ -6,10 +6,10 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return this.#x; + return this.#x + Test; } - return func(); + return func() + Test; } } -expect(Test.method()).toBe(1) +expect(Test.method()).toBe(6) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js index 20d94408b73b..5f5ffa0b2343 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/input.js @@ -6,8 +6,8 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return this.#x; + return this.#x + Test; } - return func(); + return func() + Test; } } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js index 4e85e4b2686a..8b03caa83f92 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-shadow/output.js @@ -4,10 +4,10 @@ class Test { const func = () => { const _Test = 3; - return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x); + return babelHelpers.classStaticPrivateFieldSpecGet(this, Test, _x) + _Test; }; - return func(); + return func() + _Test2; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js index 4ecedebe4259..673b1cced3af 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/exec.js @@ -6,12 +6,12 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } const t = new Test(); const t2 = new Test(); -expect(t.method(Test)).toBe(true) +expect(t.method(Test)).toBe(5) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js index 343920f28e57..faa4ce3d104a 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/input.js @@ -6,8 +6,8 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js index 64137a77f39d..898d6a8ddcfb 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-shadow/output.js @@ -4,10 +4,10 @@ class Test { const func = () => { const _Test = 3; - return other === Test; + return other === Test && _Test; }; - return func(); + return func() + _Test2; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js index 4ecedebe4259..673b1cced3af 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/exec.js @@ -6,12 +6,12 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } const t = new Test(); const t2 = new Test(); -expect(t.method(Test)).toBe(true) +expect(t.method(Test)).toBe(5) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js index 343920f28e57..faa4ce3d104a 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/input.js @@ -6,8 +6,8 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js index 64137a77f39d..898d6a8ddcfb 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-shadow/output.js @@ -4,10 +4,10 @@ class Test { const func = () => { const _Test = 3; - return other === Test; + return other === Test && _Test; }; - return func(); + return func() + _Test2; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js index 4ecedebe4259..673b1cced3af 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/exec.js @@ -6,12 +6,12 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } const t = new Test(); const t2 = new Test(); -expect(t.method(Test)).toBe(true) +expect(t.method(Test)).toBe(5) diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js index 343920f28e57..faa4ce3d104a 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/input.js @@ -6,8 +6,8 @@ class Test { const Test = 2; const func = () => { const Test = 3; - return #x in other; + return #x in other && Test; } - return func(); + return func() + Test; } } diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js index 64137a77f39d..898d6a8ddcfb 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadow/output.js @@ -4,10 +4,10 @@ class Test { const func = () => { const _Test = 3; - return other === Test; + return other === Test && _Test; }; - return func(); + return func() + _Test2; } } From 68decd2e7e829cb286d4b3eba01a9648a71f9592 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 14 Aug 2021 12:46:47 +0800 Subject: [PATCH 5/5] refactor: apply suggested changes simplify logic and add comments --- .../src/fields.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index cd4f5a48e086..0f500852c865 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -195,13 +195,15 @@ function unshadow( scope: Scope, innerBinding: t.Identifier | undefined, ) { - const binding = scope.getBinding(name); - if (innerBinding && binding && innerBinding !== binding.identifier) { - // the classRef has been shadowed, rename the local variable - while (!scope.bindingIdentifierEquals(name, innerBinding)) { - scope.rename(name); - scope = scope.parent; - } + // in some cases, scope.getBinding(name) === undefined + // so we check hasBinding to avoid keeping looping + // see: https://github.com/babel/babel/pull/13656#discussion_r686030715 + while ( + scope?.hasBinding(name) && + !scope.bindingIdentifierEquals(name, innerBinding) + ) { + scope.rename(name); + scope = scope.parent; } }