From 30802cda977f1a3f0ba2a0b7d6ff5280ac3ebddc Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 11 Aug 2017 16:14:48 -0700 Subject: [PATCH 01/11] Handle loose type parameters in Extract Method Known limitations: 1. If a type parameter on an inner symbol shadows a type parameter on an outer symbol, the generated code will be incorrect. We should either rename one or more type parameters or forbid the extraction. 2. Type arguments are always passed explicitly, even if they would be inferred correctly. --- src/compiler/types.ts | 15 +++ src/compiler/utilities.ts | 32 ++++++ src/services/refactors/extractMethod.ts | 135 ++++++++++++++++++++++-- 3 files changed, 175 insertions(+), 7 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 87ac4afbab1..64444693acf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -651,6 +651,20 @@ namespace ts { } export interface SignatureDeclaration extends NamedDeclaration { + kind: SyntaxKind.CallSignature + | SyntaxKind.ConstructSignature + | SyntaxKind.MethodSignature + | SyntaxKind.IndexSignature + | SyntaxKind.FunctionType + | SyntaxKind.ConstructorType + | SyntaxKind.JSDocFunctionType + | SyntaxKind.FunctionDeclaration + | SyntaxKind.MethodDeclaration + | SyntaxKind.Constructor + | SyntaxKind.GetAccessor + | SyntaxKind.SetAccessor + | SyntaxKind.FunctionExpression + | SyntaxKind.ArrowFunction; name?: PropertyName; typeParameters?: NodeArray; parameters: NodeArray; @@ -1816,6 +1830,7 @@ namespace ts { export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag; export interface ClassLikeDeclaration extends NamedDeclaration { + kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression; name?: Identifier; typeParameters?: NodeArray; heritageClauses?: NodeArray; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 197e91ac383..2a07d2b6560 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -477,6 +477,38 @@ namespace ts { return false; } + /* @internal */ + export function isDeclarationWithTypeParameters(node: Node): node is DeclarationWithTypeParameters; + export function isDeclarationWithTypeParameters(node: DeclarationWithTypeParameters): node is DeclarationWithTypeParameters { + switch (node.kind) { + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.JSDocFunctionType: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.JSDocTemplateTag: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return true; + default: + staticAssertNever(node); + return false; + } + } + + function staticAssertNever(_: never): void {} + // Gets the nearest enclosing block scope container that has the provided node // as a descendant, that is not the provided node. export function getEnclosingBlockScopeContainer(node: Node): Node { diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index 4fa22d24b8d..ff376026e52 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -610,7 +610,7 @@ namespace ts.refactor.extractMethod { export function extractFunctionInScope( node: Statement | Expression | Block, scope: Scope, - { usages: usagesInScope, substitutions }: ScopeUsages, + { usages: usagesInScope, typeParameterUsages, substitutions }: ScopeUsages, range: TargetRange, context: RefactorContext): ExtractResultForScope { @@ -652,7 +652,18 @@ namespace ts.refactor.extractMethod { callArguments.push(createIdentifier(name)); }); - // Provide explicit return types for contexutally-typed functions + const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ type, declaration: getFirstDeclaration(type) })); + const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder); + + const typeParameters: ReadonlyArray = sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration); + + // Strictly speaking, we should check whether each name actually binds to the appropriate type + // parameter. In cases of shadowing, they may not. + const callTypeArguments: ReadonlyArray | undefined = typeParameters.length > 0 + ? typeParameters.map(decl => createTypeReferenceNode(decl.name, /*typeArguments*/ undefined)) + : undefined; + + // Provide explicit return types for contextually-typed functions // to avoid problems when there are literal types present if (isExpression(node) && !isJS) { const contextualType = checker.getContextualType(node); @@ -677,7 +688,7 @@ namespace ts.refactor.extractMethod { range.facts & RangeFacts.IsGenerator ? createToken(SyntaxKind.AsteriskToken) : undefined, functionName, /*questionToken*/ undefined, - /*typeParameters*/[], + typeParameters, parameters, returnType, body @@ -689,7 +700,7 @@ namespace ts.refactor.extractMethod { range.facts & RangeFacts.IsAsyncFunction ? [createToken(SyntaxKind.AsyncKeyword)] : undefined, range.facts & RangeFacts.IsGenerator ? createToken(SyntaxKind.AsteriskToken) : undefined, functionName, - /*typeParameters*/[], + typeParameters, parameters, returnType, body @@ -704,7 +715,7 @@ namespace ts.refactor.extractMethod { // replace range with function call let call: Expression = createCall( isClassLike(scope) ? createPropertyAccess(range.facts & RangeFacts.InStaticRegion ? createIdentifier(scope.name.getText()) : createThis(), functionReference) : functionReference, - /*typeArguments*/ undefined, + callTypeArguments, // Note that no attempt is made to take advantage of type argument inference callArguments); if (range.facts & RangeFacts.IsGenerator) { call = createYield(createToken(SyntaxKind.AsteriskToken), call); @@ -774,6 +785,51 @@ namespace ts.refactor.extractMethod { changes: changeTracker.getChanges() }; + function getFirstDeclaration(type: Type): Declaration | undefined { + let firstDeclaration = undefined; + + const symbol = type.symbol; + if (symbol && symbol.declarations) { + for (const declaration of symbol.declarations) { + if (firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) { + firstDeclaration = declaration; + } + } + } + + return firstDeclaration; + } + + function compareTypesByDeclarationOrder( + {type: type1, declaration: declaration1}: {type: Type, declaration?: Declaration}, + {type: type2, declaration: declaration2}: {type: Type, declaration?: Declaration}) { + + if (declaration1) { + if (declaration2) { + const positionDiff = declaration1.pos - declaration2.pos; + if (positionDiff !== 0) { + return positionDiff; + } + } + else { + return 1; // Sort undeclared type parameters to the front. + } + } + else if (declaration2) { + return -1; // Sort undeclared type parameters to the front. + } + + const name1 = type1.symbol ? type1.symbol.getName() : ""; + const name2 = type2.symbol ? type2.symbol.getName() : ""; + const nameDiff = compareStrings(name1, name2); + if (nameDiff !== 0) { + return nameDiff; + } + + // IDs are guaranteed to be unique, so this ensures a total ordering. + return type1.id - type2.id; + } + function getPropertyAssignmentsForWrites(writes: UsageEntry[]) { return writes.map(w => createShorthandPropertyAssignment(w.symbol.name)); } @@ -867,6 +923,7 @@ namespace ts.refactor.extractMethod { export interface ScopeUsages { usages: Map; + typeParameterUsages: Map; // Key is type ID substitutions: Map; } @@ -877,6 +934,7 @@ namespace ts.refactor.extractMethod { sourceFile: SourceFile, checker: TypeChecker) { + const allTypeParameterUsages = createMap(); // Key is type ID const usagesPerScope: ScopeUsages[] = []; const substitutionsPerScope: Map[] = []; const errorsPerScope: Diagnostic[][] = []; @@ -884,7 +942,7 @@ namespace ts.refactor.extractMethod { // initialize results for (const _ of scopes) { - usagesPerScope.push({ usages: createMap(), substitutions: createMap() }); + usagesPerScope.push({ usages: createMap(), typeParameterUsages: createMap(), substitutions: createMap() }); substitutionsPerScope.push(createMap()); errorsPerScope.push([]); } @@ -892,8 +950,42 @@ namespace ts.refactor.extractMethod { 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) ? targetRange.range[0] : targetRange.range; + const inGenericContext = isInGenericContext(unmodifiedNode); + collectUsages(target); + if (allTypeParameterUsages.size > 0) { + const seenTypeParameterUsages = createMap(); // Key is type ID + + let i = 0; + for (let curr: Node = unmodifiedNode; curr !== undefined && i < scopes.length; curr = curr.parent) { + if (curr === scopes[i]) { + // Copy current contents of seenTypeParameterUsages into scope. + seenTypeParameterUsages.forEach((typeParameter, id) => { + usagesPerScope[i].typeParameterUsages.set(id, typeParameter); + }); + + i++; + } + + // Note that we add the current node's type parameters *after* updating the corresponding scope. + if (isDeclarationWithTypeParameters(curr) && curr.typeParameters) { + for (const typeParameterDecl of curr.typeParameters) { + const typeParameter = checker.getTypeAtLocation(typeParameterDecl) as TypeParameter; + if (allTypeParameterUsages.has(typeParameter.id.toString())) { + seenTypeParameterUsages.set(typeParameter.id.toString(), typeParameter); + } + } + } + } + + // If we didn't get through all the scopes, then there were some that weren't in our + // parent chain (impossible at time of writing). A conservative solution would be to + // copy allTypeParameterUsages into all remaining scopes. + Debug.assert(i === scopes.length); + } + for (let i = 0; i < scopes.length; i++) { let hasWrite = false; let readonlyClassPropertyWrite: Declaration | undefined = undefined; @@ -912,7 +1004,7 @@ namespace ts.refactor.extractMethod { errorsPerScope[i].push(createDiagnosticForNode(targetRange.range, Messages.CannotCombineWritesAndReturns)); } else if (readonlyClassPropertyWrite && i > 0) { - errorsPerScope[i].push(createDiagnosticForNode(readonlyClassPropertyWrite, Messages.CannotCombineWritesAndReturns)); + errorsPerScope[i].push(createDiagnosticForNode(readonlyClassPropertyWrite, Messages.CannotExtractReadonlyPropertyInitializerOutsideConstructor)); } } @@ -924,7 +1016,36 @@ namespace ts.refactor.extractMethod { return { target, usagesPerScope, errorsPerScope }; + function hasTypeParameters(node: Node) { + return isDeclarationWithTypeParameters(node) && + node.typeParameters !== undefined && + node.typeParameters.length > 0; + } + + function isInGenericContext(node: Node) { + for (; node; node = node.parent) { + if (hasTypeParameters(node)) { + return true; + } + } + + return false; + } + function collectUsages(node: Node, valueUsage = Usage.Read) { + if (inGenericContext) { + const type = checker.getTypeAtLocation(node); + + const symbolWalker = checker.getSymbolWalker(); + const {visitedTypes} = symbolWalker.walkType(type); + + for (const visitedType of visitedTypes) { + if (visitedType.flags & TypeFlags.TypeParameter) { + allTypeParameterUsages.set(visitedType.id.toString(), visitedType as TypeParameter); + } + } + } + if (isDeclaration(node) && node.symbol) { visibleDeclarationsInExtractedRange.push(node.symbol); } From b2cc7224836f498e8eb08b7841c3185c9707a3d3 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 15:44:46 -0700 Subject: [PATCH 02/11] Comment out headers in Extract Method baselines --- src/harness/unittests/extractMethods.ts | 4 ++-- .../reference/extractMethod/extractMethod1.js | 10 +++++----- .../reference/extractMethod/extractMethod10.js | 8 ++++---- .../reference/extractMethod/extractMethod11.js | 8 ++++---- .../reference/extractMethod/extractMethod12.js | 4 ++-- .../reference/extractMethod/extractMethod2.js | 10 +++++----- .../reference/extractMethod/extractMethod3.js | 10 +++++----- .../reference/extractMethod/extractMethod4.js | 10 +++++----- .../reference/extractMethod/extractMethod5.js | 10 +++++----- .../reference/extractMethod/extractMethod6.js | 10 +++++----- .../reference/extractMethod/extractMethod7.js | 10 +++++----- .../reference/extractMethod/extractMethod8.js | 10 +++++----- .../reference/extractMethod/extractMethod9.js | 10 +++++----- 13 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index d096cd3d375..c148d6d58a5 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -577,11 +577,11 @@ namespace A { assert.equal(result.errors, undefined, "expect no errors"); const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context); const data: string[] = []; - data.push(`==ORIGINAL==`); + data.push(`// ==ORIGINAL==`); data.push(sourceFile.text); for (const r of results) { const changes = refactor.extractMethod.getPossibleExtractions(result.targetRange, context, results.indexOf(r))[0].changes; - data.push(`==SCOPE::${r.scopeDescription}==`); + data.push(`// ==SCOPE::${r.scopeDescription}==`); data.push(textChanges.applyChanges(sourceFile.text, changes[0].textChanges)); } return data.join(newLineCharacter); diff --git a/tests/baselines/reference/extractMethod/extractMethod1.js b/tests/baselines/reference/extractMethod/extractMethod1.js index 10bf2648383..bfe80cb6c9b 100644 --- a/tests/baselines/reference/extractMethod/extractMethod1.js +++ b/tests/baselines/reference/extractMethod/extractMethod1.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; function foo() { @@ -14,7 +14,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; function foo() { @@ -34,7 +34,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; function foo() { @@ -55,7 +55,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; function foo() { @@ -76,7 +76,7 @@ namespace A { return a; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; function foo() { diff --git a/tests/baselines/reference/extractMethod/extractMethod10.js b/tests/baselines/reference/extractMethod/extractMethod10.js index b2397744680..97bd5cbd503 100644 --- a/tests/baselines/reference/extractMethod/extractMethod10.js +++ b/tests/baselines/reference/extractMethod/extractMethod10.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { export interface I { x: number }; class C { @@ -9,7 +9,7 @@ namespace A { } } } -==SCOPE::class 'C'== +// ==SCOPE::class 'C'== namespace A { export interface I { x: number }; class C { @@ -24,7 +24,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { export interface I { x: number }; class C { @@ -39,7 +39,7 @@ namespace A { return a1.x + 10; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { export interface I { x: number }; class C { diff --git a/tests/baselines/reference/extractMethod/extractMethod11.js b/tests/baselines/reference/extractMethod/extractMethod11.js index 21392a07a7a..4999df4a706 100644 --- a/tests/baselines/reference/extractMethod/extractMethod11.js +++ b/tests/baselines/reference/extractMethod/extractMethod11.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let y = 1; class C { @@ -11,7 +11,7 @@ namespace A { } } } -==SCOPE::class 'C'== +// ==SCOPE::class 'C'== namespace A { let y = 1; class C { @@ -30,7 +30,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let y = 1; class C { @@ -49,7 +49,7 @@ namespace A { return { __return: a1.x + 10, z }; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let y = 1; class C { diff --git a/tests/baselines/reference/extractMethod/extractMethod12.js b/tests/baselines/reference/extractMethod/extractMethod12.js index 7cebab5d3c5..2b95a545ce1 100644 --- a/tests/baselines/reference/extractMethod/extractMethod12.js +++ b/tests/baselines/reference/extractMethod/extractMethod12.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let y = 1; class C { @@ -13,7 +13,7 @@ namespace A { } } } -==SCOPE::class 'C'== +// ==SCOPE::class 'C'== namespace A { let y = 1; class C { diff --git a/tests/baselines/reference/extractMethod/extractMethod2.js b/tests/baselines/reference/extractMethod/extractMethod2.js index 3c0d2e7c7b0..3b61a98d001 100644 --- a/tests/baselines/reference/extractMethod/extractMethod2.js +++ b/tests/baselines/reference/extractMethod/extractMethod2.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; function foo() { @@ -12,7 +12,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; function foo() { @@ -30,7 +30,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; function foo() { @@ -48,7 +48,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; function foo() { @@ -66,7 +66,7 @@ namespace A { return foo(); } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; function foo() { diff --git a/tests/baselines/reference/extractMethod/extractMethod3.js b/tests/baselines/reference/extractMethod/extractMethod3.js index cb28e2755e7..0837fbfc10d 100644 --- a/tests/baselines/reference/extractMethod/extractMethod3.js +++ b/tests/baselines/reference/extractMethod/extractMethod3.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { function foo() { } @@ -11,7 +11,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { function foo() { } @@ -28,7 +28,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { function foo() { } @@ -45,7 +45,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { function foo() { } @@ -62,7 +62,7 @@ namespace A { return foo(); } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { function foo() { } diff --git a/tests/baselines/reference/extractMethod/extractMethod4.js b/tests/baselines/reference/extractMethod/extractMethod4.js index 07029b2d050..107f99e669b 100644 --- a/tests/baselines/reference/extractMethod/extractMethod4.js +++ b/tests/baselines/reference/extractMethod/extractMethod4.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { function foo() { } @@ -13,7 +13,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { function foo() { } @@ -32,7 +32,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { function foo() { } @@ -51,7 +51,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { function foo() { } @@ -70,7 +70,7 @@ namespace A { return foo(); } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { function foo() { } diff --git a/tests/baselines/reference/extractMethod/extractMethod5.js b/tests/baselines/reference/extractMethod/extractMethod5.js index 96a76e426b1..77b2f7b5545 100644 --- a/tests/baselines/reference/extractMethod/extractMethod5.js +++ b/tests/baselines/reference/extractMethod/extractMethod5.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; export function foo() { @@ -14,7 +14,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; export function foo() { @@ -34,7 +34,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; export function foo() { @@ -55,7 +55,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; export function foo() { @@ -76,7 +76,7 @@ namespace A { return a; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; export function foo() { diff --git a/tests/baselines/reference/extractMethod/extractMethod6.js b/tests/baselines/reference/extractMethod/extractMethod6.js index d1244ac9596..3c8c0a99b70 100644 --- a/tests/baselines/reference/extractMethod/extractMethod6.js +++ b/tests/baselines/reference/extractMethod/extractMethod6.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; export function foo() { @@ -14,7 +14,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; export function foo() { @@ -34,7 +34,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; export function foo() { @@ -56,7 +56,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; export function foo() { @@ -78,7 +78,7 @@ namespace A { return { __return: foo(), a }; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; export function foo() { diff --git a/tests/baselines/reference/extractMethod/extractMethod7.js b/tests/baselines/reference/extractMethod/extractMethod7.js index da400d8b051..3f1e25991bd 100644 --- a/tests/baselines/reference/extractMethod/extractMethod7.js +++ b/tests/baselines/reference/extractMethod/extractMethod7.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; export namespace C { @@ -16,7 +16,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; export namespace C { @@ -38,7 +38,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; export namespace C { @@ -62,7 +62,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; export namespace C { @@ -86,7 +86,7 @@ namespace A { return { __return: C.foo(), a }; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; export namespace C { diff --git a/tests/baselines/reference/extractMethod/extractMethod8.js b/tests/baselines/reference/extractMethod/extractMethod8.js index d298387b902..e6d933ec309 100644 --- a/tests/baselines/reference/extractMethod/extractMethod8.js +++ b/tests/baselines/reference/extractMethod/extractMethod8.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { let x = 1; namespace B { @@ -8,7 +8,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { let x = 1; namespace B { @@ -22,7 +22,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { let x = 1; namespace B { @@ -36,7 +36,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { let x = 1; namespace B { @@ -50,7 +50,7 @@ namespace A { return 1 + a1 + x; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { let x = 1; namespace B { diff --git a/tests/baselines/reference/extractMethod/extractMethod9.js b/tests/baselines/reference/extractMethod/extractMethod9.js index 609e3535d57..6d0672f11c1 100644 --- a/tests/baselines/reference/extractMethod/extractMethod9.js +++ b/tests/baselines/reference/extractMethod/extractMethod9.js @@ -1,4 +1,4 @@ -==ORIGINAL== +// ==ORIGINAL== namespace A { export interface I { x: number }; namespace B { @@ -8,7 +8,7 @@ namespace A { } } } -==SCOPE::function 'a'== +// ==SCOPE::function 'a'== namespace A { export interface I { x: number }; namespace B { @@ -22,7 +22,7 @@ namespace A { } } } -==SCOPE::namespace 'B'== +// ==SCOPE::namespace 'B'== namespace A { export interface I { x: number }; namespace B { @@ -36,7 +36,7 @@ namespace A { } } } -==SCOPE::namespace 'A'== +// ==SCOPE::namespace 'A'== namespace A { export interface I { x: number }; namespace B { @@ -50,7 +50,7 @@ namespace A { return a1.x + 10; } } -==SCOPE::global scope== +// ==SCOPE::global scope== namespace A { export interface I { x: number }; namespace B { From bf0333ae07a4088fb69c0b0509a585d3c51f66ef Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 15:53:14 -0700 Subject: [PATCH 03/11] Delete unused baselines --- tests/baselines/reference/extractMethod1.js | 98 ---------------- tests/baselines/reference/extractMethod10.js | 70 ------------ tests/baselines/reference/extractMethod11.js | 86 -------------- tests/baselines/reference/extractMethod12.js | 36 ------ tests/baselines/reference/extractMethod2.js | 85 -------------- tests/baselines/reference/extractMethod3.js | 80 ------------- tests/baselines/reference/extractMethod4.js | 90 --------------- tests/baselines/reference/extractMethod5.js | 98 ---------------- tests/baselines/reference/extractMethod6.js | 101 ----------------- tests/baselines/reference/extractMethod7.js | 111 ------------------- tests/baselines/reference/extractMethod8.js | 57 ---------- tests/baselines/reference/extractMethod9.js | 65 ----------- 12 files changed, 977 deletions(-) delete mode 100644 tests/baselines/reference/extractMethod1.js delete mode 100644 tests/baselines/reference/extractMethod10.js delete mode 100644 tests/baselines/reference/extractMethod11.js delete mode 100644 tests/baselines/reference/extractMethod12.js delete mode 100644 tests/baselines/reference/extractMethod2.js delete mode 100644 tests/baselines/reference/extractMethod3.js delete mode 100644 tests/baselines/reference/extractMethod4.js delete mode 100644 tests/baselines/reference/extractMethod5.js delete mode 100644 tests/baselines/reference/extractMethod6.js delete mode 100644 tests/baselines/reference/extractMethod7.js delete mode 100644 tests/baselines/reference/extractMethod8.js delete mode 100644 tests/baselines/reference/extractMethod9.js diff --git a/tests/baselines/reference/extractMethod1.js b/tests/baselines/reference/extractMethod1.js deleted file mode 100644 index 699916b0dc2..00000000000 --- a/tests/baselines/reference/extractMethod1.js +++ /dev/null @@ -1,98 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - let a = 1; - - let y = 5; - let z = x; - a = y; - foo(); - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - let a = 1; - - newFunction(); - - function newFunction() { - let y = 5; - let z = x; - a = y; - foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(a)); - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - foo(); - return { a }; - } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(a)); - } - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - foo(); - return { a }; - } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(x, a, foo)); - } - } -} -function newFunction(x: any, a: any, foo: any) { - let y = 5; - let z = x; - a = y; - foo(); - return { a }; -} diff --git a/tests/baselines/reference/extractMethod10.js b/tests/baselines/reference/extractMethod10.js deleted file mode 100644 index e416a66e262..00000000000 --- a/tests/baselines/reference/extractMethod10.js +++ /dev/null @@ -1,70 +0,0 @@ -==ORIGINAL== -namespace A { - export interface I { x: number }; - class C { - a() { - let z = 1; - let a1: I = { x: 1 }; - return a1.x + 10; - } - } -} -==SCOPE::method a== -namespace A { - export interface I { x: number }; - class C { - a() { - let z = 1; - return newFunction(); - - function newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } - } - } -} -==SCOPE::class C== -namespace A { - export interface I { x: number }; - class C { - a() { - let z = 1; - return this.newFunction(); - } - - private newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } - } -} -==SCOPE::namespace A== -namespace A { - export interface I { x: number }; - class C { - a() { - let z = 1; - return newFunction(); - } - } - - function newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } -} -==SCOPE::file '/a.ts'== -namespace A { - export interface I { x: number }; - class C { - a() { - let z = 1; - return newFunction(); - } - } -} -function newFunction() { - let a1: A.I = { x: 1 }; - return a1.x + 10; -} diff --git a/tests/baselines/reference/extractMethod11.js b/tests/baselines/reference/extractMethod11.js deleted file mode 100644 index 4cbd31d4453..00000000000 --- a/tests/baselines/reference/extractMethod11.js +++ /dev/null @@ -1,86 +0,0 @@ -==ORIGINAL== -namespace A { - let y = 1; - class C { - a() { - let z = 1; - let a1 = { x: 1 }; - y = 10; - z = 42; - return a1.x + 10; - } - } -} -==SCOPE::method a== -namespace A { - let y = 1; - class C { - a() { - let z = 1; - return newFunction(); - - function newFunction() { - let a1 = { x: 1 }; - y = 10; - z = 42; - return a1.x + 10; - } - } - } -} -==SCOPE::class C== -namespace A { - let y = 1; - class C { - a() { - let z = 1; - var __return: any; - ({ z, __return } = this.newFunction(z)); - return __return; - } - - private newFunction(z: any) { - let a1 = { x: 1 }; - y = 10; - z = 42; - return { z, __return: a1.x + 10 }; - } - } -} -==SCOPE::namespace A== -namespace A { - let y = 1; - class C { - a() { - let z = 1; - var __return: any; - ({ z, __return } = newFunction(z)); - return __return; - } - } - - function newFunction(z: any) { - let a1 = { x: 1 }; - y = 10; - z = 42; - return { z, __return: a1.x + 10 }; - } -} -==SCOPE::file '/a.ts'== -namespace A { - let y = 1; - class C { - a() { - let z = 1; - var __return: any; - ({ y, z, __return } = newFunction(y, z)); - return __return; - } - } -} -function newFunction(y: any, z: any) { - let a1 = { x: 1 }; - y = 10; - z = 42; - return { y, z, __return: a1.x + 10 }; -} diff --git a/tests/baselines/reference/extractMethod12.js b/tests/baselines/reference/extractMethod12.js deleted file mode 100644 index da0788a937f..00000000000 --- a/tests/baselines/reference/extractMethod12.js +++ /dev/null @@ -1,36 +0,0 @@ -==ORIGINAL== -namespace A { - let y = 1; - class C { - b() {} - a() { - let z = 1; - let a1 = { x: 1 }; - y = 10; - z = 42; - this.b(); - return a1.x + 10; - } - } -} -==SCOPE::class C== -namespace A { - let y = 1; - class C { - b() {} - a() { - let z = 1; - var __return: any; - ({ z, __return } = this.newFunction(z)); - return __return; - } - - private newFunction(z: any) { - let a1 = { x: 1 }; - y = 10; - z = 42; - this.b(); - return { z, __return: a1.x + 10 }; - } - } -} \ No newline at end of file diff --git a/tests/baselines/reference/extractMethod2.js b/tests/baselines/reference/extractMethod2.js deleted file mode 100644 index a89fe52f2fb..00000000000 --- a/tests/baselines/reference/extractMethod2.js +++ /dev/null @@ -1,85 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - - let y = 5; - let z = x; - return foo(); - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - - return newFunction(); - - function newFunction() { - let y = 5; - let z = x; - return foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - - return newFunction(); - } - - function newFunction() { - let y = 5; - let z = x; - return foo(); - } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - - return newFunction(); - } - } - - function newFunction() { - let y = 5; - let z = x; - return foo(); - } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - function foo() { - } - namespace B { - function a() { - - return newFunction(x, foo); - } - } -} -function newFunction(x: any, foo: any) { - let y = 5; - let z = x; - return foo(); -} diff --git a/tests/baselines/reference/extractMethod3.js b/tests/baselines/reference/extractMethod3.js deleted file mode 100644 index 847e196130c..00000000000 --- a/tests/baselines/reference/extractMethod3.js +++ /dev/null @@ -1,80 +0,0 @@ -==ORIGINAL== -namespace A { - function foo() { - } - namespace B { - function* a(z: number) { - - let y = 5; - yield z; - return foo(); - } - } -} -==SCOPE::function a== -namespace A { - function foo() { - } - namespace B { - function* a(z: number) { - - return yield* newFunction(); - - function* newFunction() { - let y = 5; - yield z; - return foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - function foo() { - } - namespace B { - function* a(z: number) { - - return yield* newFunction(z); - } - - function* newFunction(z: any) { - let y = 5; - yield z; - return foo(); - } - } -} -==SCOPE::namespace A== -namespace A { - function foo() { - } - namespace B { - function* a(z: number) { - - return yield* newFunction(z); - } - } - - function* newFunction(z: any) { - let y = 5; - yield z; - return foo(); - } -} -==SCOPE::file '/a.ts'== -namespace A { - function foo() { - } - namespace B { - function* a(z: number) { - - return yield* newFunction(z, foo); - } - } -} -function* newFunction(z: any, foo: any) { - let y = 5; - yield z; - return foo(); -} diff --git a/tests/baselines/reference/extractMethod4.js b/tests/baselines/reference/extractMethod4.js deleted file mode 100644 index 25f410eeecb..00000000000 --- a/tests/baselines/reference/extractMethod4.js +++ /dev/null @@ -1,90 +0,0 @@ -==ORIGINAL== -namespace A { - function foo() { - } - namespace B { - async function a(z: number, z1: any) { - - let y = 5; - if (z) { - await z1; - } - return foo(); - } - } -} -==SCOPE::function a== -namespace A { - function foo() { - } - namespace B { - async function a(z: number, z1: any) { - - return await newFunction(); - - async function newFunction() { - let y = 5; - if (z) { - await z1; - } - return foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - function foo() { - } - namespace B { - async function a(z: number, z1: any) { - - return await newFunction(z, z1); - } - - async function newFunction(z: any, z1: any) { - let y = 5; - if (z) { - await z1; - } - return foo(); - } - } -} -==SCOPE::namespace A== -namespace A { - function foo() { - } - namespace B { - async function a(z: number, z1: any) { - - return await newFunction(z, z1); - } - } - - async function newFunction(z: any, z1: any) { - let y = 5; - if (z) { - await z1; - } - return foo(); - } -} -==SCOPE::file '/a.ts'== -namespace A { - function foo() { - } - namespace B { - async function a(z: number, z1: any) { - - return await newFunction(z, z1, foo); - } - } -} -async function newFunction(z: any, z1: any, foo: any) { - let y = 5; - if (z) { - await z1; - } - return foo(); -} diff --git a/tests/baselines/reference/extractMethod5.js b/tests/baselines/reference/extractMethod5.js deleted file mode 100644 index 135c4ed5f62..00000000000 --- a/tests/baselines/reference/extractMethod5.js +++ /dev/null @@ -1,98 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - let y = 5; - let z = x; - a = y; - foo(); - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - newFunction(); - - function newFunction() { - let y = 5; - let z = x; - a = y; - foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(a)); - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - foo(); - return { a }; - } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(a)); - } - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - foo(); - return { a }; - } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - ({ a } = newFunction(x, a)); - } - } -} -function newFunction(x: any, a: any) { - let y = 5; - let z = x; - a = y; - A.foo(); - return { a }; -} diff --git a/tests/baselines/reference/extractMethod6.js b/tests/baselines/reference/extractMethod6.js deleted file mode 100644 index 94fcc8e6e31..00000000000 --- a/tests/baselines/reference/extractMethod6.js +++ /dev/null @@ -1,101 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - let y = 5; - let z = x; - a = y; - return foo(); - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - return newFunction(); - - function newFunction() { - let y = 5; - let z = x; - a = y; - return foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(a)); - return __return; - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: foo() }; - } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(a)); - return __return; - } - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: foo() }; - } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - export function foo() { - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(x, a)); - return __return; - } - } -} -function newFunction(x: any, a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: A.foo() }; -} diff --git a/tests/baselines/reference/extractMethod7.js b/tests/baselines/reference/extractMethod7.js deleted file mode 100644 index c7c3cc8d77a..00000000000 --- a/tests/baselines/reference/extractMethod7.js +++ /dev/null @@ -1,111 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - export namespace C { - export function foo() { - } - } - namespace B { - function a() { - let a = 1; - - let y = 5; - let z = x; - a = y; - return C.foo(); - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - export namespace C { - export function foo() { - } - } - namespace B { - function a() { - let a = 1; - - return newFunction(); - - function newFunction() { - let y = 5; - let z = x; - a = y; - return C.foo(); - } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - export namespace C { - export function foo() { - } - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(a)); - return __return; - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: C.foo() }; - } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - export namespace C { - export function foo() { - } - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(a)); - return __return; - } - } - - function newFunction(a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: C.foo() }; - } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - export namespace C { - export function foo() { - } - } - namespace B { - function a() { - let a = 1; - - var __return: any; - ({ a, __return } = newFunction(x, a)); - return __return; - } - } -} -function newFunction(x: any, a: any) { - let y = 5; - let z = x; - a = y; - return { a, __return: A.C.foo() }; -} diff --git a/tests/baselines/reference/extractMethod8.js b/tests/baselines/reference/extractMethod8.js deleted file mode 100644 index f030b0ea4af..00000000000 --- a/tests/baselines/reference/extractMethod8.js +++ /dev/null @@ -1,57 +0,0 @@ -==ORIGINAL== -namespace A { - let x = 1; - namespace B { - function a() { - let a1 = 1; - return 1 + a1 + x + 100; - } - } -} -==SCOPE::function a== -namespace A { - let x = 1; - namespace B { - function a() { - let a1 = 1; - return newFunction() + 100; - - function newFunction() { 1 + a1 + x; } - } - } -} -==SCOPE::namespace B== -namespace A { - let x = 1; - namespace B { - function a() { - let a1 = 1; - return newFunction(a1) + 100; - } - - function newFunction(a1: any) { 1 + a1 + x; } - } -} -==SCOPE::namespace A== -namespace A { - let x = 1; - namespace B { - function a() { - let a1 = 1; - return newFunction(a1) + 100; - } - } - - function newFunction(a1: any) { 1 + a1 + x; } -} -==SCOPE::file '/a.ts'== -namespace A { - let x = 1; - namespace B { - function a() { - let a1 = 1; - return newFunction(a1, x) + 100; - } - } -} -function newFunction(a1: any, x: any) { 1 + a1 + x; } diff --git a/tests/baselines/reference/extractMethod9.js b/tests/baselines/reference/extractMethod9.js deleted file mode 100644 index fcc5dcd23de..00000000000 --- a/tests/baselines/reference/extractMethod9.js +++ /dev/null @@ -1,65 +0,0 @@ -==ORIGINAL== -namespace A { - export interface I { x: number }; - namespace B { - function a() { - let a1: I = { x: 1 }; - return a1.x + 10; - } - } -} -==SCOPE::function a== -namespace A { - export interface I { x: number }; - namespace B { - function a() { - return newFunction(); - - function newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } - } - } -} -==SCOPE::namespace B== -namespace A { - export interface I { x: number }; - namespace B { - function a() { - return newFunction(); - } - - function newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } - } -} -==SCOPE::namespace A== -namespace A { - export interface I { x: number }; - namespace B { - function a() { - return newFunction(); - } - } - - function newFunction() { - let a1: I = { x: 1 }; - return a1.x + 10; - } -} -==SCOPE::file '/a.ts'== -namespace A { - export interface I { x: number }; - namespace B { - function a() { - return newFunction(); - } - } -} -function newFunction() { - let a1: A.I = { x: 1 }; - return a1.x + 10; -} From ee80019d1625a519088c0c93cfb7794b544522b2 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 15:53:41 -0700 Subject: [PATCH 04/11] Switch from .js to .ts so that baselines are syntactically valid --- src/harness/unittests/extractMethods.ts | 2 +- .../extractMethod/{extractMethod1.js => extractMethod1.ts} | 0 .../extractMethod/{extractMethod10.js => extractMethod10.ts} | 0 .../extractMethod/{extractMethod11.js => extractMethod11.ts} | 0 .../extractMethod/{extractMethod12.js => extractMethod12.ts} | 0 .../extractMethod/{extractMethod2.js => extractMethod2.ts} | 0 .../extractMethod/{extractMethod3.js => extractMethod3.ts} | 0 .../extractMethod/{extractMethod4.js => extractMethod4.ts} | 0 .../extractMethod/{extractMethod5.js => extractMethod5.ts} | 0 .../extractMethod/{extractMethod6.js => extractMethod6.ts} | 0 .../extractMethod/{extractMethod7.js => extractMethod7.ts} | 0 .../extractMethod/{extractMethod8.js => extractMethod8.ts} | 0 .../extractMethod/{extractMethod9.js => extractMethod9.ts} | 0 13 files changed, 1 insertion(+), 1 deletion(-) rename tests/baselines/reference/extractMethod/{extractMethod1.js => extractMethod1.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod10.js => extractMethod10.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod11.js => extractMethod11.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod12.js => extractMethod12.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod2.js => extractMethod2.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod3.js => extractMethod3.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod4.js => extractMethod4.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod5.js => extractMethod5.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod6.js => extractMethod6.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod7.js => extractMethod7.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod8.js => extractMethod8.ts} (100%) rename tests/baselines/reference/extractMethod/{extractMethod9.js => extractMethod9.ts} (100%) diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index c148d6d58a5..971d918cb33 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -550,7 +550,7 @@ namespace A { function testExtractMethod(caption: string, text: string) { it(caption, () => { - Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => { + Harness.Baseline.runBaseline(`extractMethod/${caption}.ts`, () => { const t = extractTest(text); const selectionRange = t.ranges.get("selection"); if (!selectionRange) { diff --git a/tests/baselines/reference/extractMethod/extractMethod1.js b/tests/baselines/reference/extractMethod/extractMethod1.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod1.js rename to tests/baselines/reference/extractMethod/extractMethod1.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod10.js b/tests/baselines/reference/extractMethod/extractMethod10.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod10.js rename to tests/baselines/reference/extractMethod/extractMethod10.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod11.js b/tests/baselines/reference/extractMethod/extractMethod11.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod11.js rename to tests/baselines/reference/extractMethod/extractMethod11.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod12.js b/tests/baselines/reference/extractMethod/extractMethod12.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod12.js rename to tests/baselines/reference/extractMethod/extractMethod12.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod2.js b/tests/baselines/reference/extractMethod/extractMethod2.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod2.js rename to tests/baselines/reference/extractMethod/extractMethod2.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod3.js b/tests/baselines/reference/extractMethod/extractMethod3.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod3.js rename to tests/baselines/reference/extractMethod/extractMethod3.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod4.js b/tests/baselines/reference/extractMethod/extractMethod4.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod4.js rename to tests/baselines/reference/extractMethod/extractMethod4.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod5.js b/tests/baselines/reference/extractMethod/extractMethod5.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod5.js rename to tests/baselines/reference/extractMethod/extractMethod5.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod6.js b/tests/baselines/reference/extractMethod/extractMethod6.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod6.js rename to tests/baselines/reference/extractMethod/extractMethod6.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod7.js b/tests/baselines/reference/extractMethod/extractMethod7.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod7.js rename to tests/baselines/reference/extractMethod/extractMethod7.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod8.js b/tests/baselines/reference/extractMethod/extractMethod8.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod8.js rename to tests/baselines/reference/extractMethod/extractMethod8.ts diff --git a/tests/baselines/reference/extractMethod/extractMethod9.js b/tests/baselines/reference/extractMethod/extractMethod9.ts similarity index 100% rename from tests/baselines/reference/extractMethod/extractMethod9.js rename to tests/baselines/reference/extractMethod/extractMethod9.ts From b09d2277b8d4797419738b29c97e5d682c6fe0f4 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 16:13:20 -0700 Subject: [PATCH 05/11] Test that in-scope type parameters are not passed explicitly --- src/harness/unittests/extractMethods.ts | 21 ++++++ .../extractMethod/extractMethod13.ts | 75 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/baselines/reference/extractMethod/extractMethod13.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 971d918cb33..36f739113ab 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -544,6 +544,27 @@ namespace A { return a1.x + 10;|] } } +}`); + // The "b" type parameters aren't used and shouldn't be passed to the extracted function. + // Type parameters should be in syntactic order (i.e. in order or character offset from BOF). + // In all cases, we could use type inference, rather than passing explicit type arguments. + // Note the inclusion of arrow functions to ensure that some type parameters are not from + // targetable scopes. + testExtractMethod("extractMethod13", + `(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + [#|t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString();|] + } + } + } + } }`); }); diff --git a/tests/baselines/reference/extractMethod/extractMethod13.ts b/tests/baselines/reference/extractMethod/extractMethod13.ts new file mode 100644 index 00000000000..8f76dea88aa --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod13.ts @@ -0,0 +1,75 @@ +// ==ORIGINAL== +(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString(); + } + } + } + } +} +// ==SCOPE::function 'F2'== +(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + newFunction(u3a); + } + + function newFunction(u3a: U3a) { + t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString(); + } + } + } + } +} +// ==SCOPE::function 'F1'== +(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + newFunction(t2a, u2a, u3a); + } + } + } + + function newFunction(t2a: T2a, u2a: U2a, u3a: U3a) { + t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString(); + } + } +} +// ==SCOPE::global scope== +(u1a: U1a, u1b: U1b) => { + function F1(t1a: T1a, t1b: T1b) { + (u2a: U2a, u2b: U2b) => { + function F2(t2a: T2a, t2b: T2b) { + (u3a: U3a, u3b: U3b) => { + newFunction(t1a, t2a, u1a, u2a, u3a); + } + } + } + } +} +function newFunction(t1a: T1a, t2a: T2a, u1a: U1a, u2a: U2a, u3a: U3a) { + t1a.toString(); + t2a.toString(); + u1a.toString(); + u2a.toString(); + u3a.toString(); +} From fe015ef30fde86ffa4c3eeb89ffe699b5d1eec52 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 16:35:53 -0700 Subject: [PATCH 06/11] Document failure to handle type parameter shadowing --- src/harness/unittests/extractMethods.ts | 9 +++++ .../extractMethod/extractMethod14.ts | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/baselines/reference/extractMethod/extractMethod14.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 36f739113ab..a7cc73b5b51 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -565,6 +565,15 @@ namespace A { } } } +}`); + // This test is descriptive, rather than normative. The current implementation + // doesn't handle type parameter shadowing. + testExtractMethod("extractMethod14", + `function F(t1: T) { + function F(t2: T) { + [#|t1.toString(); + t2.toString();|] + } }`); }); diff --git a/tests/baselines/reference/extractMethod/extractMethod14.ts b/tests/baselines/reference/extractMethod/extractMethod14.ts new file mode 100644 index 00000000000..38e4c380ebc --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod14.ts @@ -0,0 +1,39 @@ +// ==ORIGINAL== +function F(t1: T) { + function F(t2: T) { + t1.toString(); + t2.toString(); + } +} +// ==SCOPE::function 'F'== +function F(t1: T) { + function F(t2: T) { + newFunction(); + + function newFunction() { + t1.toString(); + t2.toString(); + } + } +} +// ==SCOPE::function 'F'== +function F(t1: T) { + function F(t2: T) { + newFunction(t2); + } + + function newFunction(t2: T) { + t1.toString(); + t2.toString(); + } +} +// ==SCOPE::global scope== +function F(t1: T) { + function F(t2: T) { + newFunction(t1, t2); + } +} +function newFunction(t1: T, t2: T) { + t1.toString(); + t2.toString(); +} From 0c8d85fbc4154487a5677fb95ecf717fb22bf7d8 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 16:54:57 -0700 Subject: [PATCH 07/11] Test that type parameters used in constraints are passed along --- src/harness/unittests/extractMethods.ts | 9 ++++- .../extractMethod/extractMethod15.ts | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/extractMethod/extractMethod15.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index a7cc73b5b51..43984fc21b8 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -574,6 +574,13 @@ namespace A { [#|t1.toString(); t2.toString();|] } +}`); + // Confirm that the constraint is preserved. + testExtractMethod("extractMethod15", + `function F(t1: T) { + function F(t2: U) { + [#|t2.toString();|] + } }`); }); @@ -590,7 +597,7 @@ namespace A { path: "/a.ts", content: t.source }; - const host = projectSystem.createServerHost([f]); + const host = projectSystem.createServerHost([f, projectSystem.libFile]); const projectService = projectSystem.createProjectService(host); projectService.openClientFile(f.path); const program = projectService.inferredProjects[0].getLanguageService().getProgram(); diff --git a/tests/baselines/reference/extractMethod/extractMethod15.ts b/tests/baselines/reference/extractMethod/extractMethod15.ts new file mode 100644 index 00000000000..ba5b9b3ad01 --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod15.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== +function F(t1: T) { + function F(t2: U) { + t2.toString(); + } +} +// ==SCOPE::function 'F'== +function F(t1: T) { + function F(t2: U) { + newFunction(); + + function newFunction() { + t2.toString(); + } + } +} +// ==SCOPE::function 'F'== +function F(t1: T) { + function F(t2: U) { + newFunction(t2); + } + + function newFunction(t2: U) { + t2.toString(); + } +} +// ==SCOPE::global scope== +function F(t1: T) { + function F(t2: U) { + newFunction(t2); + } +} +function newFunction(t2: U) { + t2.toString(); +} From 01d7f0b699def1d9f9d3045bbe6fcb0c72079fb8 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Aug 2017 17:50:50 -0700 Subject: [PATCH 08/11] Test that the return type of the extracted method counts as usage --- src/harness/unittests/extractMethods.ts | 5 ++++ src/services/refactors/extractMethod.ts | 30 +++++++++++++------ .../extractMethod/extractMethod16.ts | 19 ++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/extractMethod/extractMethod16.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 43984fc21b8..7d7125c5025 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -581,6 +581,11 @@ namespace A { function F(t2: U) { [#|t2.toString();|] } +}`); + // Confirm that the contextual type of an extracted expression counts as a use. + testExtractMethod("extractMethod16", + `function F() { + const array: T[] = [#|[]|]; }`); }); diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index ff376026e52..b02cb607e04 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -946,6 +946,7 @@ namespace ts.refactor.extractMethod { substitutionsPerScope.push(createMap()); errorsPerScope.push([]); } + 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]); @@ -955,6 +956,14 @@ namespace ts.refactor.extractMethod { collectUsages(target); + // Unfortunately, this code takes advantage of the knowledge that the generated method + // will use the contextual type of an expression as the return type of the extracted + // method (and will therefore "use" all the types involved). + if (inGenericContext && !isReadonlyArray(targetRange.range)) { + const contextualType = checker.getContextualType(targetRange.range); + recordTypeParameterUsages(contextualType); + } + if (allTypeParameterUsages.size > 0) { const seenTypeParameterUsages = createMap(); // Key is type ID @@ -1032,18 +1041,21 @@ namespace ts.refactor.extractMethod { return false; } + function recordTypeParameterUsages(type: Type) { + const symbolWalker = checker.getSymbolWalker(); + const {visitedTypes} = symbolWalker.walkType(type); + + for (const visitedType of visitedTypes) { + if (visitedType.flags & TypeFlags.TypeParameter) { + allTypeParameterUsages.set(visitedType.id.toString(), visitedType as TypeParameter); + } + } + } + function collectUsages(node: Node, valueUsage = Usage.Read) { if (inGenericContext) { const type = checker.getTypeAtLocation(node); - - const symbolWalker = checker.getSymbolWalker(); - const {visitedTypes} = symbolWalker.walkType(type); - - for (const visitedType of visitedTypes) { - if (visitedType.flags & TypeFlags.TypeParameter) { - allTypeParameterUsages.set(visitedType.id.toString(), visitedType as TypeParameter); - } - } + recordTypeParameterUsages(type); } if (isDeclaration(node) && node.symbol) { diff --git a/tests/baselines/reference/extractMethod/extractMethod16.ts b/tests/baselines/reference/extractMethod/extractMethod16.ts new file mode 100644 index 00000000000..1ce88b93145 --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod16.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== +function F() { + const array: T[] = []; +} +// ==SCOPE::function 'F'== +function F() { + const array: T[] = newFunction(); + + function newFunction(): T[] { + return []; + } +} +// ==SCOPE::global scope== +function F() { + const array: T[] = newFunction(); +} +function newFunction(): T[] { + return []; +} From e08dce2c21a251e88e51db49d389ac12bcea3373 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 17 Aug 2017 14:54:25 -0700 Subject: [PATCH 09/11] Test different parameters on classes and methods --- src/harness/unittests/extractMethods.ts | 14 +++++++++++ .../extractMethod/extractMethod17.ts | 25 +++++++++++++++++++ .../extractMethod/extractMethod18.ts | 25 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 tests/baselines/reference/extractMethod/extractMethod17.ts create mode 100644 tests/baselines/reference/extractMethod/extractMethod18.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 7d7125c5025..227f6b22b03 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -586,6 +586,20 @@ namespace A { testExtractMethod("extractMethod16", `function F() { const array: T[] = [#|[]|]; +}`); + // Class type parameter + testExtractMethod("extractMethod17", + `class C { + M(t1: T1, t2: T2) { + [#|t1.toString()|]; + } +}`); + // Method type parameter + testExtractMethod("extractMethod18", + `class C { + M(t1: T1, t2: T2) { + [#|t1.toString()|]; + } }`); }); diff --git a/tests/baselines/reference/extractMethod/extractMethod17.ts b/tests/baselines/reference/extractMethod/extractMethod17.ts new file mode 100644 index 00000000000..d800c79f3bd --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod17.ts @@ -0,0 +1,25 @@ +// ==ORIGINAL== +class C { + M(t1: T1, t2: T2) { + t1.toString(); + } +} +// ==SCOPE::class 'C'== +class C { + M(t1: T1, t2: T2) { + this.newFunction(t1); + } + + private newFunction(t1: T1) { + t1.toString(); + } +} +// ==SCOPE::global scope== +class C { + M(t1: T1, t2: T2) { + newFunction(t1); + } +} +function newFunction(t1: T1) { + t1.toString(); +} diff --git a/tests/baselines/reference/extractMethod/extractMethod18.ts b/tests/baselines/reference/extractMethod/extractMethod18.ts new file mode 100644 index 00000000000..ce6a90c3790 --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod18.ts @@ -0,0 +1,25 @@ +// ==ORIGINAL== +class C { + M(t1: T1, t2: T2) { + t1.toString(); + } +} +// ==SCOPE::class 'C'== +class C { + M(t1: T1, t2: T2) { + this.newFunction(t1); + } + + private newFunction(t1: T1) { + t1.toString(); + } +} +// ==SCOPE::global scope== +class C { + M(t1: T1, t2: T2) { + newFunction(t1); + } +} +function newFunction(t1: T1) { + t1.toString(); +} From c9f6bc60e2f345c59653aa40221cad8ca6f0a1dd Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 17 Aug 2017 15:14:36 -0700 Subject: [PATCH 10/11] Test coupling of type parameters --- src/harness/unittests/extractMethods.ts | 5 +++++ .../extractMethod/extractMethod19.ts | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/baselines/reference/extractMethod/extractMethod19.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 227f6b22b03..a7741a56f59 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -600,6 +600,11 @@ namespace A { M(t1: T1, t2: T2) { [#|t1.toString()|]; } +}`); + // Coupled constraints + testExtractMethod("extractMethod19", + `function F(v: V) { + [#|v.toString()|]; }`); }); diff --git a/tests/baselines/reference/extractMethod/extractMethod19.ts b/tests/baselines/reference/extractMethod/extractMethod19.ts new file mode 100644 index 00000000000..1bf25550172 --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod19.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== +function F(v: V) { + v.toString(); +} +// ==SCOPE::function 'F'== +function F(v: V) { + newFunction(); + + function newFunction() { + v.toString(); + } +} +// ==SCOPE::global scope== +function F(v: V) { + newFunction(v); +} +function newFunction(v: V) { + v.toString(); +} From a816079ddad974b7d62c1368767e60d72371311b Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 17 Aug 2017 16:24:44 -0700 Subject: [PATCH 11/11] Add perf comment --- src/services/refactors/extractMethod.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index b02cb607e04..5e1a96aa1fb 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -1042,6 +1042,9 @@ namespace ts.refactor.extractMethod { } function recordTypeParameterUsages(type: Type) { + // PERF: This is potentially very expensive. `type` could be a library type with + // a lot of properties, each of which the walker will visit. Unfortunately, the + // solution isn't as trivial as filtering to user types because of (e.g.) Array. const symbolWalker = checker.getSymbolWalker(); const {visitedTypes} = symbolWalker.walkType(type);