diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 2370c23f9efbe..6f88629f8e3ef 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -1,4 +1,3 @@ - namespace FourSlash { import ArrayOrSingle = FourSlashInterface.ArrayOrSingle; @@ -3481,8 +3480,18 @@ namespace FourSlash { public verifyRefactorAvailable(negative: boolean, triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string, actionDescription?: string) { let refactors = this.getApplicableRefactorsAtSelection(triggerReason); - refactors = refactors.filter(r => - r.name === name && (actionName === undefined || r.actions.some(a => a.name === actionName)) && (actionDescription === undefined || r.actions.some(a => a.description === actionDescription))); + refactors = refactors.filter(r => r.name === name); + + if (actionName !== undefined) { + refactors.forEach(r => r.actions = r.actions.filter(a => a.name === actionName)); + } + + if (actionDescription !== undefined) { + refactors.forEach(r => r.actions = r.actions.filter(a => a.description === actionDescription)); + } + + refactors = refactors.filter(r => r.actions.length > 0); + const isAvailable = refactors.length > 0; if (negative) { diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 51db88025325f..9f3a0521144ea 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -69,8 +69,8 @@ namespace ts.refactor.extractSymbol { let i = 0; for (const { functionExtraction, constantExtraction } of extractions) { - const description = functionExtraction.description; if (refactorKindBeginsWith(extractFunctionAction.kind, requestedRefactor)) { + const description = functionExtraction.description; if (functionExtraction.errors.length === 0) { // Don't issue refactorings with duplicated names. // Scopes come back in "innermost first" order, so extractions will @@ -95,11 +95,11 @@ namespace ts.refactor.extractSymbol { } if (refactorKindBeginsWith(extractConstantAction.kind, requestedRefactor)) { + const description = constantExtraction.description; if (constantExtraction.errors.length === 0) { // Don't issue refactorings with duplicated names. // Scopes come back in "innermost first" order, so extractions will // preferentially go into nearer scopes - const description = constantExtraction.description; if (!usedConstantNames.has(description)) { usedConstantNames.set(description, true); constantActions.push({ diff --git a/tests/cases/fourslash/server/fixExtractToInnerFunctionDuplicaton.ts b/tests/cases/fourslash/server/fixExtractToInnerFunctionDuplicaton.ts new file mode 100644 index 0000000000000..e782b26388f72 --- /dev/null +++ b/tests/cases/fourslash/server/fixExtractToInnerFunctionDuplicaton.ts @@ -0,0 +1,14 @@ +/// + +//// function foo(): void { /*x*/console.log('a');/*y*/ } + +goTo.select("x","y"); +verify.refactorAvailable("Extract Symbol", 'function_scope_0', "Extract to inner function in function 'foo'"); +verify.refactorAvailable("Extract Symbol", 'function_scope_1', "Extract to function in global scope"); + +verify.not.refactorAvailable("Extract Symbol", 'constant_scope_0', "Extract to inner function in function 'foo'"); + +verify.refactorAvailable("Extract Symbol", 'constant_scope_0', "Extract to constant in enclosing scope"); +verify.refactorAvailable("Extract Symbol", 'constant_scope_1', "Extract to constant in global scope"); + +verify.not.refactorAvailable("Extract Symbol", 'constant_scope_0', "Extract to constant in global scope"); \ No newline at end of file