diff --git a/src/harness/unittests/extractFunctions.ts b/src/harness/unittests/extractFunctions.ts index 750e590ca4c..715a4f5aa0c 100644 --- a/src/harness/unittests/extractFunctions.ts +++ b/src/harness/unittests/extractFunctions.ts @@ -360,6 +360,142 @@ function parsePrimaryExpression(): any { export const j = 10; export const y = [#|j * j|]; }`); + + testExtractFunction("extractFunction_VariableDeclaration_Var", ` +[#|var x = 1;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Let_Type", ` +[#|let x: number = 1;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Let_NoType", ` +[#|let x = 1;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Const_Type", ` +[#|const x: number = 1;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Const_NoType", ` +[#|const x = 1;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Multiple1", ` +[#|const x = 1, y: string = "a";|] +x; y; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Multiple2", ` +[#|const x = 1, y = "a"; +const z = 3;|] +x; y; z; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Multiple3", ` +[#|const x = 1, y: string = "a"; +let z = 3;|] +x; y; z; +`); + + testExtractFunction("extractFunction_VariableDeclaration_ConsumedTwice", ` +[#|const x: number = 1;|] +x; x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_DeclaredTwice", ` +[#|var x = 1; +var x = 2;|] +x; +`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Var", ` +function f() { + let a = 1; + [#|var x = 1; + a++;|] + a; x; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_NoType", ` +function f() { + let a = 1; + [#|let x = 1; + a++;|] + a; x; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_Type", ` +function f() { + let a = 1; + [#|let x: number = 1; + a++;|] + a; x; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Const_NoType", ` +function f() { + let a = 1; + [#|const x = 1; + a++;|] + a; x; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Const_Type", ` +function f() { + let a = 1; + [#|const x: number = 1; + a++;|] + a; x; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed1", ` +function f() { + let a = 1; + [#|const x = 1; + let y = 2; + a++;|] + a; x; y; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed2", ` +function f() { + let a = 1; + [#|var x = 1; + let y = 2; + a++;|] + a; x; y; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed3", ` +function f() { + let a = 1; + [#|let x: number = 1; + let y = 2; + a++;|] + a; x; y; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_Writes_UnionUndefined", ` +function f() { + let a = 1; + [#|let x: number | undefined = 1; + let y: undefined | number = 2; + let z: (undefined | number) = 3; + a++;|] + a; x; y; z; +}`); + + testExtractFunction("extractFunction_VariableDeclaration_ShorthandProperty", ` +function f() { + [#|let x;|] + return { x }; +}`); }); function testExtractFunction(caption: string, text: string) { diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 9defe3dd1f0..a03bb843600 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -137,7 +137,7 @@ namespace ts.refactor.extractSymbol { export const FunctionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); export const CannotExtractIdentifier = createMessage("Select more than a single identifier."); export const CannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); - export const CannotCombineWritesAndReturns = createMessage("Cannot combine writes and returns"); + export const CannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression"); 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"); @@ -507,15 +507,16 @@ namespace ts.refactor.extractSymbol { } function getFunctionExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); + const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); Debug.assert(!functionErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); context.cancellationToken.throwIfCancellationRequested(); - return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context); + return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], exposedVariableDeclarations, targetRange, context); } function getConstantExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); + const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); Debug.assert(!constantErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); + Debug.assert(exposedVariableDeclarations.length === 0, "Extract constant accepted a range containing a variable declaration?"); context.cancellationToken.throwIfCancellationRequested(); const expression = isExpression(target) ? target @@ -674,6 +675,7 @@ namespace ts.refactor.extractSymbol { node: Statement | Expression | Block, scope: Scope, { usages: usagesInScope, typeParameterUsages, substitutions }: ScopeUsages, + exposedVariableDeclarations: ReadonlyArray, range: TargetRange, context: RefactorContext): RefactorEditInfo { @@ -731,10 +733,10 @@ namespace ts.refactor.extractSymbol { // to avoid problems when there are literal types present if (isExpression(node) && !isJS) { const contextualType = checker.getContextualType(node); - returnType = checker.typeToTypeNode(contextualType); + returnType = checker.typeToTypeNode(contextualType, scope, NodeBuilderFlags.NoTruncation); } - const { body, returnValueProperty } = transformFunctionBody(node, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)); + const { body, returnValueProperty } = transformFunctionBody(node, exposedVariableDeclarations, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)); let newFunction: MethodDeclaration | FunctionDeclaration; if (isClassLike(scope)) { @@ -796,38 +798,114 @@ namespace ts.refactor.extractSymbol { call = createAwait(call); } - if (writes) { + if (exposedVariableDeclarations.length && !writes) { + // No need to mix declarations and writes. + + // How could any variables be exposed if there's a return statement? + Debug.assert(!returnValueProperty); + Debug.assert(!(range.facts & RangeFacts.HasReturn)); + + if (exposedVariableDeclarations.length === 1) { + // Declaring exactly one variable: let x = newFunction(); + const variableDeclaration = exposedVariableDeclarations[0]; + newNodes.push(createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + [createVariableDeclaration(getSynthesizedDeepClone(variableDeclaration.name), /*type*/ getSynthesizedDeepClone(variableDeclaration.type), /*initializer*/ call)], // TODO (acasey): test binding patterns + variableDeclaration.parent.flags))); + } + else { + // Declaring multiple variables / return properties: + // let {x, y} = newFunction(); + const bindingElements: BindingElement[] = []; + const typeElements: TypeElement[] = []; + let commonNodeFlags = exposedVariableDeclarations[0].parent.flags; + let sawExplicitType = false; + for (const variableDeclaration of exposedVariableDeclarations) { + bindingElements.push(createBindingElement( + /*dotDotDotToken*/ undefined, + /*propertyName*/ undefined, + /*name*/ getSynthesizedDeepClone(variableDeclaration.name))); + + // Being returned through an object literal will have widened the type. + const variableType: TypeNode = checker.typeToTypeNode( + checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(variableDeclaration)), + scope, + NodeBuilderFlags.NoTruncation); + + typeElements.push(createPropertySignature( + /*modifiers*/ undefined, + /*name*/ variableDeclaration.symbol.name, + /*questionToken*/ undefined, + /*type*/ variableType, + /*initializer*/ undefined)); + sawExplicitType = sawExplicitType || variableDeclaration.type !== undefined; + commonNodeFlags = commonNodeFlags & variableDeclaration.parent.flags; + } + + const typeLiteral: TypeLiteralNode | undefined = sawExplicitType ? createTypeLiteralNode(typeElements) : undefined; + if (typeLiteral) { + setEmitFlags(typeLiteral, EmitFlags.SingleLine); + } + + newNodes.push(createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + [createVariableDeclaration( + createObjectBindingPattern(bindingElements), + /*type*/ typeLiteral, + /*initializer*/call)], + commonNodeFlags))); + } + } + else if (exposedVariableDeclarations.length || writes) { + if (exposedVariableDeclarations.length) { + // CONSIDER: we're going to create one statement per variable, but we could actually preserve their original grouping. + for (const variableDeclaration of exposedVariableDeclarations) { + let flags: NodeFlags = variableDeclaration.parent.flags; + if (flags & NodeFlags.Const) { + flags = (flags & ~NodeFlags.Const) | NodeFlags.Let; + } + + newNodes.push(createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + [createVariableDeclaration(variableDeclaration.symbol.name, getTypeDeepCloneUnionUndefined(variableDeclaration.type))], + flags))); + } + } + if (returnValueProperty) { // has both writes and return, need to create variable declaration to hold return value; newNodes.push(createVariableStatement( /*modifiers*/ undefined, - [createVariableDeclaration(returnValueProperty, createKeywordTypeNode(SyntaxKind.AnyKeyword))] - )); + createVariableDeclarationList( + [createVariableDeclaration(returnValueProperty, getTypeDeepCloneUnionUndefined(returnType))], + NodeFlags.Let))); } - const assignments = getPropertyAssignmentsForWrites(writes); + const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); if (returnValueProperty) { assignments.unshift(createShorthandPropertyAssignment(returnValueProperty)); } // propagate writes back if (assignments.length === 1) { - if (returnValueProperty) { - newNodes.push(createReturn(createIdentifier(returnValueProperty))); - } - else { - newNodes.push(createStatement(createBinary(assignments[0].name, SyntaxKind.EqualsToken, call))); + // We would only have introduced a return value property if there had been + // other assignments to make. + Debug.assert(!returnValueProperty); - if (range.facts & RangeFacts.HasReturn) { - newNodes.push(createReturn()); - } + newNodes.push(createStatement(createAssignment(assignments[0].name, call))); + + if (range.facts & RangeFacts.HasReturn) { + newNodes.push(createReturn()); } } else { // emit e.g. // { a, b, __return } = newFunction(a, b); // return __return; - newNodes.push(createStatement(createBinary(createObjectLiteral(assignments), SyntaxKind.EqualsToken, call))); + newNodes.push(createStatement(createAssignment(createObjectLiteral(assignments), call))); if (returnValueProperty) { newNodes.push(createReturn(createIdentifier(returnValueProperty))); } @@ -861,6 +939,21 @@ namespace ts.refactor.extractSymbol { const renameFilename = renameRange.getSourceFile().fileName; const renameLocation = getRenameLocation(edits, renameFilename, functionNameText, /*isDeclaredBeforeUse*/ false); return { renameFilename, renameLocation, edits }; + + function getTypeDeepCloneUnionUndefined(typeNode: TypeNode | undefined): TypeNode | undefined { + if (typeNode === undefined) { + return undefined; + } + + const clone = getSynthesizedDeepClone(typeNode); + let withoutParens = clone; + while (isParenthesizedTypeNode(withoutParens)) { + withoutParens = withoutParens.type; + } + return isUnionTypeNode(withoutParens) && find(withoutParens.types, t => t.kind === SyntaxKind.UndefinedKeyword) + ? clone + : createUnionTypeNode([clone, createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + } } /** @@ -883,7 +976,7 @@ namespace ts.refactor.extractSymbol { const variableType = isJS ? undefined - : checker.typeToTypeNode(checker.getContextualType(node)); + : checker.typeToTypeNode(checker.getContextualType(node), scope, NodeBuilderFlags.NoTruncation); const initializer = transformConstantInitializer(node, substitutions); @@ -1088,21 +1181,22 @@ namespace ts.refactor.extractSymbol { } } - function transformFunctionBody(body: Node, writes: ReadonlyArray, substitutions: ReadonlyMap, hasReturn: boolean): { body: Block, returnValueProperty: string } { - if (isBlock(body) && !writes && substitutions.size === 0) { - // already block, no writes to propagate back, no substitutions - can use node as is + function transformFunctionBody(body: Node, exposedVariableDeclarations: ReadonlyArray, writes: ReadonlyArray, substitutions: ReadonlyMap, hasReturn: boolean): { body: Block, returnValueProperty: string } { + const hasWritesOrVariableDeclarations = writes !== undefined || exposedVariableDeclarations.length > 0; + if (isBlock(body) && !hasWritesOrVariableDeclarations && substitutions.size === 0) { + // already block, no declarations or writes to propagate back, no substitutions - can use node as is return { body: createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined }; } let returnValueProperty: string; let ignoreReturns = false; const statements = createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : createReturn(body)]); // rewrite body if either there are writes that should be propagated back via return statements or there are substitutions - if (writes || substitutions.size) { + if (hasWritesOrVariableDeclarations || substitutions.size) { const rewrittenStatements = visitNodes(statements, visitor).slice(); - if (writes && !hasReturn && isStatement(body)) { + if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) { // add return at the end to propagate writes back in case if control flow falls out of the function body // it is ok to know that range has at least one return since it we only allow unconditional returns - const assignments = getPropertyAssignmentsForWrites(writes); + const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); if (assignments.length === 1) { rewrittenStatements.push(createReturn(assignments[0].name)); } @@ -1117,8 +1211,8 @@ namespace ts.refactor.extractSymbol { } function visitor(node: Node): VisitResult { - if (!ignoreReturns && node.kind === SyntaxKind.ReturnStatement && writes) { - const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWrites(writes); + if (!ignoreReturns && node.kind === SyntaxKind.ReturnStatement && hasWritesOrVariableDeclarations) { + const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); if ((node).expression) { if (!returnValueProperty) { returnValueProperty = "__return"; @@ -1240,8 +1334,18 @@ namespace ts.refactor.extractSymbol { } } - function getPropertyAssignmentsForWrites(writes: ReadonlyArray): ShorthandPropertyAssignment[] { - return writes.map(w => createShorthandPropertyAssignment(w.symbol.name)); + function getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations: ReadonlyArray, + writes: ReadonlyArray) { + + const variableAssignments = map(exposedVariableDeclarations, v => createShorthandPropertyAssignment(v.symbol.name)); + const writeAssignments = map(writes, w => createShorthandPropertyAssignment(w.symbol.name)); + + return variableAssignments === undefined + ? writeAssignments + : writeAssignments === undefined + ? variableAssignments + : variableAssignments.concat(writeAssignments); } function isReadonlyArray(v: any): v is ReadonlyArray { @@ -1287,6 +1391,7 @@ namespace ts.refactor.extractSymbol { readonly usagesPerScope: ReadonlyArray; readonly functionErrorsPerScope: ReadonlyArray>; readonly constantErrorsPerScope: ReadonlyArray>; + readonly exposedVariableDeclarations: ReadonlyArray; } function collectReadsAndWrites( targetRange: TargetRange, @@ -1301,7 +1406,10 @@ namespace ts.refactor.extractSymbol { const substitutionsPerScope: Map[] = []; const functionErrorsPerScope: Diagnostic[][] = []; const constantErrorsPerScope: Diagnostic[][] = []; - const visibleDeclarationsInExtractedRange: Symbol[] = []; + const visibleDeclarationsInExtractedRange: NamedDeclaration[] = []; + const exposedVariableSymbolSet = createMap(); // Key is symbol ID + const exposedVariableDeclarations: VariableDeclaration[] = []; + let firstExposedNonVariableDeclaration: NamedDeclaration | undefined = undefined; const expression = !isReadonlyArray(targetRange.range) ? targetRange.range @@ -1346,7 +1454,6 @@ namespace ts.refactor.extractSymbol { const seenUsages = createMap(); const target = isReadonlyArray(targetRange.range) ? createBlock(targetRange.range) : targetRange.range; - const containingLexicalScopeOfExtraction = isBlockScope(scopes[0], scopes[0].parent) ? scopes[0] : getEnclosingBlockScopeContainer(scopes[0]); const unmodifiedNode = isReadonlyArray(targetRange.range) ? first(targetRange.range) : targetRange.range; const inGenericContext = isInGenericContext(unmodifiedNode); @@ -1392,6 +1499,15 @@ namespace ts.refactor.extractSymbol { Debug.assert(i === scopes.length); } + // If there are any declarations in the extracted block that are used in the same enclosing + // lexical scope, we can't move the extraction "up" as those declarations will become unreachable + if (visibleDeclarationsInExtractedRange.length) { + const containingLexicalScopeOfExtraction = isBlockScope(scopes[0], scopes[0].parent) + ? scopes[0] + : getEnclosingBlockScopeContainer(scopes[0]); + forEachChild(containingLexicalScopeOfExtraction, checkForUsedDeclarations); + } + for (let i = 0; i < scopes.length; i++) { const scopeUsages = usagesPerScope[i]; // Special case: in the innermost scope, all usages are available. @@ -1415,8 +1531,11 @@ namespace ts.refactor.extractSymbol { } }); - if (hasWrite && !isReadonlyArray(targetRange.range) && isExpression(targetRange.range)) { - const diag = createDiagnosticForNode(targetRange.range, Messages.CannotCombineWritesAndReturns); + // If an expression was extracted, then there shouldn't have been any variable declarations. + Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0); + + if (hasWrite && !isReadonlyArray(targetRange.range)) { + const diag = createDiagnosticForNode(targetRange.range, Messages.CannotWriteInExpression); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } @@ -1425,15 +1544,14 @@ namespace ts.refactor.extractSymbol { functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } + else if (firstExposedNonVariableDeclaration) { + const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.CannotExtractExportedEntity); + functionErrorsPerScope[i].push(diag); + constantErrorsPerScope[i].push(diag); + } } - // If there are any declarations in the extracted block that are used in the same enclosing - // lexical scope, we can't move the extraction "up" as those declarations will become unreachable - if (visibleDeclarationsInExtractedRange.length) { - forEachChild(containingLexicalScopeOfExtraction, checkForUsedDeclarations); - } - - return { target, usagesPerScope, functionErrorsPerScope, constantErrorsPerScope }; + return { target, usagesPerScope, functionErrorsPerScope, constantErrorsPerScope, exposedVariableDeclarations }; function hasTypeParameters(node: Node) { return isDeclarationWithTypeParameters(node) && @@ -1472,7 +1590,7 @@ namespace ts.refactor.extractSymbol { } if (isDeclaration(node) && node.symbol) { - visibleDeclarationsInExtractedRange.push(node.symbol); + visibleDeclarationsInExtractedRange.push(node); } if (isAssignmentExpression(node)) { @@ -1518,11 +1636,7 @@ namespace ts.refactor.extractSymbol { } function recordUsagebySymbol(identifier: Identifier, usage: Usage, isTypeName: boolean) { - // If the identifier is both a property name and its value, we're only interested in its value - // (since the name is a declaration and will be included in the extracted range). - const symbol = identifier.parent && isShorthandPropertyAssignment(identifier.parent) && identifier.parent.name === identifier - ? checker.getShorthandAssignmentValueSymbol(identifier.parent) - : checker.getSymbolAtLocation(identifier); + const symbol = getSymbolReferencedByIdentifier(identifier); if (!symbol) { // cannot find symbol - do nothing return undefined; @@ -1606,20 +1720,39 @@ namespace ts.refactor.extractSymbol { } // Otherwise check and recurse. - const sym = checker.getSymbolAtLocation(node); - if (sym && visibleDeclarationsInExtractedRange.some(d => d === sym)) { - const diag = createDiagnosticForNode(node, Messages.CannotExtractExportedEntity); - for (const errors of functionErrorsPerScope) { - errors.push(diag); + const sym = isIdentifier(node) + ? getSymbolReferencedByIdentifier(node) + : checker.getSymbolAtLocation(node); + if (sym) { + const decl = find(visibleDeclarationsInExtractedRange, d => d.symbol === sym); + if (decl) { + if (isVariableDeclaration(decl)) { + const idString = decl.symbol.id.toString(); + if (!exposedVariableSymbolSet.has(idString)) { + exposedVariableDeclarations.push(decl); + exposedVariableSymbolSet.set(idString, true); + } + } + else { + // CONSIDER: this includes binding elements, which we could + // expose in the same way as variables. + firstExposedNonVariableDeclaration = firstExposedNonVariableDeclaration || decl; + } } - for (const errors of constantErrorsPerScope) { - errors.push(diag); - } - return true; - } - else { - forEachChild(node, checkForUsedDeclarations); } + + forEachChild(node, checkForUsedDeclarations); + } + + /** + * Return the symbol referenced by an identifier (even if it declares a different symbol). + */ + function getSymbolReferencedByIdentifier(identifier: Identifier) { + // If the identifier is both a property name and its value, we're only interested in its value + // (since the name is a declaration and will be included in the extracted range). + return identifier.parent && isShorthandPropertyAssignment(identifier.parent) && identifier.parent.name === identifier + ? checker.getShorthandAssignmentValueSymbol(identifier.parent) + : checker.getSymbolAtLocation(identifier); } function tryReplaceWithQualifiedNameOrPropertyAccess(symbol: Symbol, scopeDecl: Node, isTypeNode: boolean): PropertyAccessExpression | EntityName { diff --git a/tests/baselines/reference/extractFunction/extractFunction11.ts b/tests/baselines/reference/extractFunction/extractFunction11.ts index d07a1826439..4bb88123a2f 100644 --- a/tests/baselines/reference/extractFunction/extractFunction11.ts +++ b/tests/baselines/reference/extractFunction/extractFunction11.ts @@ -17,7 +17,7 @@ namespace A { class C { a() { let z = 1; - var __return: any; + let __return; ({ __return, z } = this./*RENAME*/newMethod(z)); return __return; } @@ -36,7 +36,7 @@ namespace A { class C { a() { let z = 1; - var __return: any; + let __return; ({ __return, z } = /*RENAME*/newFunction(z)); return __return; } @@ -55,7 +55,7 @@ namespace A { class C { a() { let z = 1; - var __return: any; + let __return; ({ __return, y, z } = /*RENAME*/newFunction(y, z)); return __return; } diff --git a/tests/baselines/reference/extractFunction/extractFunction12.ts b/tests/baselines/reference/extractFunction/extractFunction12.ts index 37274bdcc87..49e87151b9b 100644 --- a/tests/baselines/reference/extractFunction/extractFunction12.ts +++ b/tests/baselines/reference/extractFunction/extractFunction12.ts @@ -20,7 +20,7 @@ namespace A { b() {} a() { let z = 1; - var __return: any; + let __return; ({ __return, z } = this./*RENAME*/newMethod(z)); return __return; } diff --git a/tests/baselines/reference/extractFunction/extractFunction6.ts b/tests/baselines/reference/extractFunction/extractFunction6.ts index f6c94216b46..a01cb25e061 100644 --- a/tests/baselines/reference/extractFunction/extractFunction6.ts +++ b/tests/baselines/reference/extractFunction/extractFunction6.ts @@ -43,7 +43,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(a)); return __return; } @@ -65,7 +65,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(a)); return __return; } @@ -87,7 +87,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(x, a)); return __return; } diff --git a/tests/baselines/reference/extractFunction/extractFunction7.ts b/tests/baselines/reference/extractFunction/extractFunction7.ts index 91377868e0f..4111558904c 100644 --- a/tests/baselines/reference/extractFunction/extractFunction7.ts +++ b/tests/baselines/reference/extractFunction/extractFunction7.ts @@ -49,7 +49,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(a)); return __return; } @@ -73,7 +73,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(a)); return __return; } @@ -97,7 +97,7 @@ namespace A { function a() { let a = 1; - var __return: any; + let __return; ({ __return, a } = /*RENAME*/newFunction(x, a)); return __return; } diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.js new file mode 100644 index 00000000000..fff1488ef41 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.js @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +const x = /*RENAME*/newFunction(); +x; + +function newFunction() { + const x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.ts new file mode 100644 index 00000000000..fff1488ef41 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_NoType.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +const x = /*RENAME*/newFunction(); +x; + +function newFunction() { + const x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_Type.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_Type.ts new file mode 100644 index 00000000000..94576953758 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Const_Type.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/const x: number = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +const x: number = /*RENAME*/newFunction(); +x; + +function newFunction() { + const x: number = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ConsumedTwice.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ConsumedTwice.ts new file mode 100644 index 00000000000..ac57711614c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ConsumedTwice.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/const x: number = 1;/*|]*/ +x; x; + +// ==SCOPE::Extract to function in global scope== + +const x: number = /*RENAME*/newFunction(); +x; x; + +function newFunction() { + const x: number = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.js new file mode 100644 index 00000000000..e6f314acd9c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.js @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +/*[#|*/var x = 1; +var x = 2;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +var x = /*RENAME*/newFunction(); +x; + +function newFunction() { + var x = 1; + var x = 2; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.ts new file mode 100644 index 00000000000..e6f314acd9c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_DeclaredTwice.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +/*[#|*/var x = 1; +var x = 2;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +var x = /*RENAME*/newFunction(); +x; + +function newFunction() { + var x = 1; + var x = 2; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.js new file mode 100644 index 00000000000..4f407ce5703 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.js @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/let x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +let x = /*RENAME*/newFunction(); +x; + +function newFunction() { + let x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.ts new file mode 100644 index 00000000000..4f407ce5703 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_NoType.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/let x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +let x = /*RENAME*/newFunction(); +x; + +function newFunction() { + let x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_Type.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_Type.ts new file mode 100644 index 00000000000..048b77094ea --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Let_Type.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/let x: number = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +let x: number = /*RENAME*/newFunction(); +x; + +function newFunction() { + let x: number = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple1.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple1.ts new file mode 100644 index 00000000000..07ec452e360 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple1.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1, y: string = "a";/*|]*/ +x; y; + +// ==SCOPE::Extract to function in global scope== + +const { x, y }: { x: number; y: string; } = /*RENAME*/newFunction(); +x; y; + +function newFunction() { + const x = 1, y: string = "a"; + return { x, y }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.js new file mode 100644 index 00000000000..c58c39bf6b8 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.js @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1, y = "a"; +const z = 3;/*|]*/ +x; y; z; + +// ==SCOPE::Extract to function in global scope== + +const { x, y, z } = /*RENAME*/newFunction(); +x; y; z; + +function newFunction() { + const x = 1, y = "a"; + const z = 3; + return { x, y, z }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.ts new file mode 100644 index 00000000000..c58c39bf6b8 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple2.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1, y = "a"; +const z = 3;/*|]*/ +x; y; z; + +// ==SCOPE::Extract to function in global scope== + +const { x, y, z } = /*RENAME*/newFunction(); +x; y; z; + +function newFunction() { + const x = 1, y = "a"; + const z = 3; + return { x, y, z }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple3.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple3.ts new file mode 100644 index 00000000000..b8ae2b72883 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Multiple3.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +/*[#|*/const x = 1, y: string = "a"; +let z = 3;/*|]*/ +x; y; z; + +// ==SCOPE::Extract to function in global scope== + +var { x, y, z }: { x: number; y: string; z: number; } = /*RENAME*/newFunction(); +x; y; z; + +function newFunction() { + const x = 1, y: string = "a"; + let z = 3; + return { x, y, z }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.js new file mode 100644 index 00000000000..67b4f64290c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.js @@ -0,0 +1,27 @@ +// ==ORIGINAL== + +function f() { + /*[#|*/let x;/*|]*/ + return { x }; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let x = /*RENAME*/newFunction(); + return { x }; + + function newFunction() { + let x; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let x = /*RENAME*/newFunction(); + return { x }; +} +function newFunction() { + let x; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.ts new file mode 100644 index 00000000000..67b4f64290c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_ShorthandProperty.ts @@ -0,0 +1,27 @@ +// ==ORIGINAL== + +function f() { + /*[#|*/let x;/*|]*/ + return { x }; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let x = /*RENAME*/newFunction(); + return { x }; + + function newFunction() { + let x; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let x = /*RENAME*/newFunction(); + return { x }; +} +function newFunction() { + let x; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.js new file mode 100644 index 00000000000..5a784c366c1 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.js @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/var x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +var x = /*RENAME*/newFunction(); +x; + +function newFunction() { + var x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.ts new file mode 100644 index 00000000000..5a784c366c1 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Var.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +/*[#|*/var x = 1;/*|]*/ +x; + +// ==SCOPE::Extract to function in global scope== + +var x = /*RENAME*/newFunction(); +x; + +function newFunction() { + var x = 1; + return x; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.js new file mode 100644 index 00000000000..1da5a568333 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.js @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/const x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + const x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + const x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a) { + const x = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.ts new file mode 100644 index 00000000000..f93f43ceebf --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_NoType.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/const x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + const x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + const x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a: number) { + const x = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_Type.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_Type.ts new file mode 100644 index 00000000000..ec846f7f288 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Const_Type.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/const x: number = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + const x: number = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + const x: number = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x: number | undefined; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a: number) { + const x: number = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.js new file mode 100644 index 00000000000..2f298c8719f --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.js @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/let x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + let x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + let x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a) { + let x = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.ts new file mode 100644 index 00000000000..e4afefa9da6 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_NoType.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/let x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + let x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + let x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a: number) { + let x = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_Type.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_Type.ts new file mode 100644 index 00000000000..795effbeb7e --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Let_Type.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/let x: number = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + let x: number = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + let x: number = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x: number | undefined; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a: number) { + let x: number = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.js new file mode 100644 index 00000000000..c36557847f7 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.js @@ -0,0 +1,38 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/const x = 1; + let y = 2; + a++;/*|]*/ + a; x; y; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var { x, y } = /*RENAME*/newFunction(); + a; x; y; + + function newFunction() { + const x = 1; + let y = 2; + a++; + return { x, y }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + let y; + ({ x, y, a } = /*RENAME*/newFunction(a)); + a; x; y; +} +function newFunction(a) { + const x = 1; + let y = 2; + a++; + return { x, y, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.ts new file mode 100644 index 00000000000..eaeb781bc48 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed1.ts @@ -0,0 +1,38 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/const x = 1; + let y = 2; + a++;/*|]*/ + a; x; y; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var { x, y } = /*RENAME*/newFunction(); + a; x; y; + + function newFunction() { + const x = 1; + let y = 2; + a++; + return { x, y }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x; + let y; + ({ x, y, a } = /*RENAME*/newFunction(a)); + a; x; y; +} +function newFunction(a: number) { + const x = 1; + let y = 2; + a++; + return { x, y, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.js new file mode 100644 index 00000000000..2d1151a549c --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.js @@ -0,0 +1,38 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/var x = 1; + let y = 2; + a++;/*|]*/ + a; x; y; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var { x, y } = /*RENAME*/newFunction(); + a; x; y; + + function newFunction() { + var x = 1; + let y = 2; + a++; + return { x, y }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + var x; + let y; + ({ x, y, a } = /*RENAME*/newFunction(a)); + a; x; y; +} +function newFunction(a) { + var x = 1; + let y = 2; + a++; + return { x, y, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.ts new file mode 100644 index 00000000000..9466b5dc37f --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed2.ts @@ -0,0 +1,38 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/var x = 1; + let y = 2; + a++;/*|]*/ + a; x; y; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var { x, y } = /*RENAME*/newFunction(); + a; x; y; + + function newFunction() { + var x = 1; + let y = 2; + a++; + return { x, y }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + var x; + let y; + ({ x, y, a } = /*RENAME*/newFunction(a)); + a; x; y; +} +function newFunction(a: number) { + var x = 1; + let y = 2; + a++; + return { x, y, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed3.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed3.ts new file mode 100644 index 00000000000..604d2a33c43 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Mixed3.ts @@ -0,0 +1,38 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/let x: number = 1; + let y = 2; + a++;/*|]*/ + a; x; y; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + let { x, y }: { x: number; y: number; } = /*RENAME*/newFunction(); + a; x; y; + + function newFunction() { + let x: number = 1; + let y = 2; + a++; + return { x, y }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x: number | undefined; + let y; + ({ x, y, a } = /*RENAME*/newFunction(a)); + a; x; y; +} +function newFunction(a: number) { + let x: number = 1; + let y = 2; + a++; + return { x, y, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_UnionUndefined.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_UnionUndefined.ts new file mode 100644 index 00000000000..0cf71e45e28 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_UnionUndefined.ts @@ -0,0 +1,42 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/let x: number | undefined = 1; + let y: undefined | number = 2; + let z: (undefined | number) = 3; + a++;/*|]*/ + a; x; y; z; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + let { x, y, z }: { x: number; y: number; z: number; } = /*RENAME*/newFunction(); + a; x; y; z; + + function newFunction() { + let x: number | undefined = 1; + let y: undefined | number = 2; + let z: (undefined | number) = 3; + a++; + return { x, y, z }; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + let x: number | undefined; + let y: undefined | number; + let z: (undefined | number); + ({ x, y, z, a } = /*RENAME*/newFunction(a)); + a; x; y; z; +} +function newFunction(a: number) { + let x: number | undefined = 1; + let y: undefined | number = 2; + let z: (undefined | number) = 3; + a++; + return { x, y, z, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.js b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.js new file mode 100644 index 00000000000..25e910713d8 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.js @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/var x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + var x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + var x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a) { + var x = 1; + a++; + return { x, a }; +} diff --git a/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.ts b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.ts new file mode 100644 index 00000000000..e215e3d0978 --- /dev/null +++ b/tests/baselines/reference/extractFunction/extractFunction_VariableDeclaration_Writes_Var.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function f() { + let a = 1; + /*[#|*/var x = 1; + a++;/*|]*/ + a; x; +} +// ==SCOPE::Extract to inner function in function 'f'== + +function f() { + let a = 1; + var x = /*RENAME*/newFunction(); + a; x; + + function newFunction() { + var x = 1; + a++; + return x; + } +} +// ==SCOPE::Extract to function in global scope== + +function f() { + let a = 1; + var x; + ({ x, a } = /*RENAME*/newFunction(a)); + a; x; +} +function newFunction(a: number) { + var x = 1; + a++; + return { x, a }; +} diff --git a/tests/cases/fourslash/extract-method14.ts b/tests/cases/fourslash/extract-method14.ts index ea051aabbe7..ddfd8cbcbd6 100644 --- a/tests/cases/fourslash/extract-method14.ts +++ b/tests/cases/fourslash/extract-method14.ts @@ -18,7 +18,7 @@ edit.applyRefactor({ newContent: `function foo() { var i = 10; - var __return: any; + let __return; ({ __return, i } = /*RENAME*/newFunction(i)); return __return; }