From a3c6f139a0b4f684bd26b987a2cdf8dedd0ea75a Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 20 May 2021 17:20:35 +0100 Subject: [PATCH] Init --- src/services/refactors/extractSymbol.ts | 6 +----- .../unittests/services/extract/functions.ts | 5 +++++ .../extractFunction/extractFunction10.ts | 15 ++++++++++++++ .../extractFunction/extractFunction11.ts | 17 ++++++++++++++++ .../extractFunction/extractFunction12.ts | 19 ++++++++++++++++++ .../extractFunction/extractFunction13.ts | 20 +++++++++++++++++++ .../extractFunction/extractFunction17.ts | 10 ++++++++++ .../extractFunction/extractFunction18.ts | 10 ++++++++++ .../extractFunction/extractFunction20.js | 11 ++++++++++ .../extractFunction/extractFunction20.ts | 11 ++++++++++ .../extractFunction/extractFunction26.js | 12 +++++++++++ .../extractFunction/extractFunction26.ts | 12 +++++++++++ .../extractFunction/extractFunction27.js | 13 ++++++++++++ .../extractFunction/extractFunction27.ts | 13 ++++++++++++ .../extractFunction/extractFunction28.js | 13 ++++++++++++ .../extractFunction/extractFunction28.ts | 13 ++++++++++++ .../extractFunction/extractFunction31.ts | 16 +++++++++++++++ .../extractFunction/extractFunction32.ts | 17 ++++++++++++++++ .../extractFunction/extractFunction34.js | 20 +++++++++++++++++++ .../extractFunction/extractFunction34.ts | 20 +++++++++++++++++++ .../extractFunction_NamelessClass.js | 11 ++++++++++ .../extractFunction_NamelessClass.ts | 11 ++++++++++ tests/cases/fourslash/extract-method20.ts | 2 +- 23 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/extractFunction/extractFunction34.js create mode 100644 tests/baselines/reference/extractFunction/extractFunction34.ts diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 832725a9cda14..3824e5821028d 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -215,7 +215,6 @@ namespace ts.refactor.extractSymbol { export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); export const cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); export const cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); - export const cannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function"); export const cannotExtractToJSClass = createMessage("Cannot extract constant to a class scope in JS"); export const cannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block"); } @@ -1624,10 +1623,7 @@ namespace ts.refactor.extractSymbol { usagesPerScope.push({ usages: new Map(), typeParameterUsages: new Map(), substitutions: new Map() }); substitutionsPerScope.push(new Map()); - functionErrorsPerScope.push( - isFunctionLikeDeclaration(scope) && scope.kind !== SyntaxKind.FunctionDeclaration - ? [createDiagnosticForNode(scope, Messages.cannotExtractToOtherFunctionLike)] - : []); + functionErrorsPerScope.push([]); const constantErrors = []; if (expressionDiagnostic) { diff --git a/src/testRunner/unittests/services/extract/functions.ts b/src/testRunner/unittests/services/extract/functions.ts index 6f7eecce05a64..c0e0a4b21f5ec 100644 --- a/src/testRunner/unittests/services/extract/functions.ts +++ b/src/testRunner/unittests/services/extract/functions.ts @@ -352,6 +352,11 @@ function parsePrimaryExpression(): any { `function F() { [#|function G() { }|] }`); + // Arrow function + testExtractFunction("extractFunction34", + `const F = () => { + [#|function G() { }|] +};`); testExtractFunction("extractFunction_RepeatedSubstitution", `namespace X { diff --git a/tests/baselines/reference/extractFunction/extractFunction10.ts b/tests/baselines/reference/extractFunction/extractFunction10.ts index 99651f03e88d1..539a0be78b861 100644 --- a/tests/baselines/reference/extractFunction/extractFunction10.ts +++ b/tests/baselines/reference/extractFunction/extractFunction10.ts @@ -9,6 +9,21 @@ namespace A { } } } +// ==SCOPE::Extract to inner function in method 'a'== +namespace A { + export interface I { x: number }; + class C { + a() { + let z = 1; + return /*RENAME*/newFunction(); + + function newFunction() { + let a1: I = { x: 1 }; + return a1.x + 10; + } + } + } +} // ==SCOPE::Extract to method in class 'C'== namespace A { export interface I { x: number }; diff --git a/tests/baselines/reference/extractFunction/extractFunction11.ts b/tests/baselines/reference/extractFunction/extractFunction11.ts index baca3914b039c..b1c60592269ad 100644 --- a/tests/baselines/reference/extractFunction/extractFunction11.ts +++ b/tests/baselines/reference/extractFunction/extractFunction11.ts @@ -11,6 +11,23 @@ namespace A { } } } +// ==SCOPE::Extract to inner function in method 'a'== +namespace A { + let y = 1; + class C { + a() { + let z = 1; + return /*RENAME*/newFunction(); + + function newFunction() { + let a1 = { x: 1 }; + y = 10; + z = 42; + return a1.x + 10; + } + } + } +} // ==SCOPE::Extract to method in class 'C'== namespace A { let y = 1; diff --git a/tests/baselines/reference/extractFunction/extractFunction12.ts b/tests/baselines/reference/extractFunction/extractFunction12.ts index 49e87151b9ba7..f9215e9b36fe3 100644 --- a/tests/baselines/reference/extractFunction/extractFunction12.ts +++ b/tests/baselines/reference/extractFunction/extractFunction12.ts @@ -13,6 +13,25 @@ namespace A { } } } +// ==SCOPE::Extract to inner function in method 'a'== +namespace A { + let y = 1; + class C { + b() {} + a() { + let z = 1; + return /*RENAME*/newFunction(); + + function newFunction() { + let a1 = { x: 1 }; + y = 10; + z = 42; + this.b(); + return a1.x + 10; + } + } + } +} // ==SCOPE::Extract to method in class 'C'== namespace A { let y = 1; diff --git a/tests/baselines/reference/extractFunction/extractFunction13.ts b/tests/baselines/reference/extractFunction/extractFunction13.ts index e39476160c567..647c72a009f5e 100644 --- a/tests/baselines/reference/extractFunction/extractFunction13.ts +++ b/tests/baselines/reference/extractFunction/extractFunction13.ts @@ -14,6 +14,26 @@ } } } +// ==SCOPE::Extract to inner function in arrow function== +(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + /*RENAME*/newFunction(); + + function newFunction() { + t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString(); + } + } + } + } + } +} // ==SCOPE::Extract to inner function in function 'F2'== (u1a: U1a, u1b: U1b) => { function F1(t1a: T1a, t1b: T1b) { diff --git a/tests/baselines/reference/extractFunction/extractFunction17.ts b/tests/baselines/reference/extractFunction/extractFunction17.ts index 45d9953fb9504..5f86f013cde1e 100644 --- a/tests/baselines/reference/extractFunction/extractFunction17.ts +++ b/tests/baselines/reference/extractFunction/extractFunction17.ts @@ -4,6 +4,16 @@ class C { /*[#|*/t1.toString()/*|]*/; } } +// ==SCOPE::Extract to inner function in method 'M'== +class C { + M(t1: T1, t2: T2) { + /*RENAME*/newFunction(); + + function newFunction() { + t1.toString(); + } + } +} // ==SCOPE::Extract to method in class 'C'== class C { M(t1: T1, t2: T2) { diff --git a/tests/baselines/reference/extractFunction/extractFunction18.ts b/tests/baselines/reference/extractFunction/extractFunction18.ts index bdfcce6bbdc69..4f5e08264cd3f 100644 --- a/tests/baselines/reference/extractFunction/extractFunction18.ts +++ b/tests/baselines/reference/extractFunction/extractFunction18.ts @@ -4,6 +4,16 @@ class C { /*[#|*/t1.toString()/*|]*/; } } +// ==SCOPE::Extract to inner function in method 'M'== +class C { + M(t1: T1, t2: T2) { + /*RENAME*/newFunction(); + + function newFunction() { + t1.toString(); + } + } +} // ==SCOPE::Extract to method in class 'C'== class C { M(t1: T1, t2: T2) { diff --git a/tests/baselines/reference/extractFunction/extractFunction20.js b/tests/baselines/reference/extractFunction/extractFunction20.js index 17bef1c604450..db847b528d64d 100644 --- a/tests/baselines/reference/extractFunction/extractFunction20.js +++ b/tests/baselines/reference/extractFunction/extractFunction20.js @@ -5,6 +5,17 @@ const _ = class { return a1.x + 10;/*|]*/ } } +// ==SCOPE::Extract to inner function in method 'a'== +const _ = class { + a() { + return /*RENAME*/newFunction(); + + function newFunction() { + let a1 = { x: 1 }; + return a1.x + 10; + } + } +} // ==SCOPE::Extract to method in anonymous class expression== const _ = class { a() { diff --git a/tests/baselines/reference/extractFunction/extractFunction20.ts b/tests/baselines/reference/extractFunction/extractFunction20.ts index ce09d4457d30a..041727e60dfbf 100644 --- a/tests/baselines/reference/extractFunction/extractFunction20.ts +++ b/tests/baselines/reference/extractFunction/extractFunction20.ts @@ -5,6 +5,17 @@ const _ = class { return a1.x + 10;/*|]*/ } } +// ==SCOPE::Extract to inner function in method 'a'== +const _ = class { + a() { + return /*RENAME*/newFunction(); + + function newFunction() { + let a1 = { x: 1 }; + return a1.x + 10; + } + } +} // ==SCOPE::Extract to method in anonymous class expression== const _ = class { a() { diff --git a/tests/baselines/reference/extractFunction/extractFunction26.js b/tests/baselines/reference/extractFunction/extractFunction26.js index 2c821c05ad107..1c95e4d1006df 100644 --- a/tests/baselines/reference/extractFunction/extractFunction26.js +++ b/tests/baselines/reference/extractFunction/extractFunction26.js @@ -6,6 +6,18 @@ class C { } M3() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + M3() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction26.ts b/tests/baselines/reference/extractFunction/extractFunction26.ts index 300686c12abca..088b0144bc1c5 100644 --- a/tests/baselines/reference/extractFunction/extractFunction26.ts +++ b/tests/baselines/reference/extractFunction/extractFunction26.ts @@ -6,6 +6,18 @@ class C { } M3() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + M3() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction27.js b/tests/baselines/reference/extractFunction/extractFunction27.js index 702127b9d76ca..a23c67d410f26 100644 --- a/tests/baselines/reference/extractFunction/extractFunction27.js +++ b/tests/baselines/reference/extractFunction/extractFunction27.js @@ -7,6 +7,19 @@ class C { constructor() { } M3() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + constructor() { } + M3() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction27.ts b/tests/baselines/reference/extractFunction/extractFunction27.ts index 1acbe67707a30..e20b70e3e765b 100644 --- a/tests/baselines/reference/extractFunction/extractFunction27.ts +++ b/tests/baselines/reference/extractFunction/extractFunction27.ts @@ -7,6 +7,19 @@ class C { constructor() { } M3() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + constructor() { } + M3() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction28.js b/tests/baselines/reference/extractFunction/extractFunction28.js index cf0742626dd98..46b237b744402 100644 --- a/tests/baselines/reference/extractFunction/extractFunction28.js +++ b/tests/baselines/reference/extractFunction/extractFunction28.js @@ -7,6 +7,19 @@ class C { M3() { } constructor() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + M3() { } + constructor() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction28.ts b/tests/baselines/reference/extractFunction/extractFunction28.ts index f15d7956f1c00..3553c416af1dc 100644 --- a/tests/baselines/reference/extractFunction/extractFunction28.ts +++ b/tests/baselines/reference/extractFunction/extractFunction28.ts @@ -7,6 +7,19 @@ class C { M3() { } constructor() { } } +// ==SCOPE::Extract to inner function in method 'M2'== +class C { + M1() { } + M2() { + return /*RENAME*/newFunction(); + + function newFunction() { + return 1; + } + } + M3() { } + constructor() { } +} // ==SCOPE::Extract to method in class 'C'== class C { M1() { } diff --git a/tests/baselines/reference/extractFunction/extractFunction31.ts b/tests/baselines/reference/extractFunction/extractFunction31.ts index 2dea17689b6fb..05a74deb8628b 100644 --- a/tests/baselines/reference/extractFunction/extractFunction31.ts +++ b/tests/baselines/reference/extractFunction/extractFunction31.ts @@ -10,6 +10,22 @@ namespace N { }/*|]*/ } } +// ==SCOPE::Extract to inner function in arrow function== +namespace N { + + export const value = 1; + + () => { + var f: () => number; + /*RENAME*/newFunction(); + + function newFunction() { + f = function(): number { + return value; + }; + } + } +} // ==SCOPE::Extract to function in namespace 'N'== namespace N { diff --git a/tests/baselines/reference/extractFunction/extractFunction32.ts b/tests/baselines/reference/extractFunction/extractFunction32.ts index acd5ac50804d2..75a16495cfcb1 100644 --- a/tests/baselines/reference/extractFunction/extractFunction32.ts +++ b/tests/baselines/reference/extractFunction/extractFunction32.ts @@ -11,6 +11,23 @@ namespace N { }/*|]*/ } } +// ==SCOPE::Extract to inner function in arrow function== +namespace N { + + export const value = 1; + + () => { + var c = /*RENAME*/newFunction() + + function newFunction() { + return class { + M() { + return value; + } + }; + } + } +} // ==SCOPE::Extract to function in namespace 'N'== namespace N { diff --git a/tests/baselines/reference/extractFunction/extractFunction34.js b/tests/baselines/reference/extractFunction/extractFunction34.js new file mode 100644 index 0000000000000..e97dec0b986c2 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction34.js @@ -0,0 +1,20 @@ +// ==ORIGINAL== +const F = () => { + /*[#|*/function G() { }/*|]*/ +}; +// ==SCOPE::Extract to inner function in arrow function== +const F = () => { + /*RENAME*/newFunction(); + + function newFunction() { + function G() { } + } +}; +// ==SCOPE::Extract to function in global scope== +const F = () => { + /*RENAME*/newFunction(); +}; + +function newFunction() { + function G() { } +} diff --git a/tests/baselines/reference/extractFunction/extractFunction34.ts b/tests/baselines/reference/extractFunction/extractFunction34.ts new file mode 100644 index 0000000000000..e97dec0b986c2 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction34.ts @@ -0,0 +1,20 @@ +// ==ORIGINAL== +const F = () => { + /*[#|*/function G() { }/*|]*/ +}; +// ==SCOPE::Extract to inner function in arrow function== +const F = () => { + /*RENAME*/newFunction(); + + function newFunction() { + function G() { } + } +}; +// ==SCOPE::Extract to function in global scope== +const F = () => { + /*RENAME*/newFunction(); +}; + +function newFunction() { + function G() { } +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.js b/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.js index f0c42044996d7..e5b3ba0efb94c 100644 --- a/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.js +++ b/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.js @@ -5,6 +5,17 @@ export default class { /*[#|*/1 + 1/*|]*/; } } +// ==SCOPE::Extract to inner function in method 'M'== + +export default class { + M() { + /*RENAME*/newFunction(); + + function newFunction() { + 1 + 1; + } + } +} // ==SCOPE::Extract to method in anonymous class declaration== export default class { diff --git a/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.ts b/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.ts index 9905cd08c743f..7ea8c9cebdb66 100644 --- a/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.ts +++ b/tests/baselines/reference/extractFunction/extractFunction_NamelessClass.ts @@ -5,6 +5,17 @@ export default class { /*[#|*/1 + 1/*|]*/; } } +// ==SCOPE::Extract to inner function in method 'M'== + +export default class { + M() { + /*RENAME*/newFunction(); + + function newFunction() { + 1 + 1; + } + } +} // ==SCOPE::Extract to method in anonymous class declaration== export default class { diff --git a/tests/cases/fourslash/extract-method20.ts b/tests/cases/fourslash/extract-method20.ts index bd137c55d1975..c64895dfc4d72 100644 --- a/tests/cases/fourslash/extract-method20.ts +++ b/tests/cases/fourslash/extract-method20.ts @@ -10,6 +10,6 @@ //// } goTo.select('a', 'b') -verify.not.refactorAvailable('Extract Symbol', 'function_scope_0'); +verify.refactorAvailable('Extract Symbol', 'function_scope_0'); verify.refactorAvailable('Extract Symbol', 'function_scope_1'); verify.not.refactorAvailable('Extract Symbol', 'function_scope_2');