From 3f59aa9871509ece6d4e688cb1eb314c2cffaa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Fri, 10 Aug 2018 09:05:28 +0800 Subject: [PATCH 01/20] stash --- src/compiler/diagnosticMessages.json | 20 ++++++++ src/services/codefixes/returnValueSurmise.ts | 50 ++++++++++++++++++++ src/services/tsconfig.json | 1 + 3 files changed, 71 insertions(+) create mode 100644 src/services/codefixes/returnValueSurmise.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5d4d9ae701d38..f4c03e6698823 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4563,5 +4563,25 @@ "Add all missing imports": { "category": "Message", "code": 95064 + }, + "Add a return statement": { + "category": "Message", + "code": 95065 + }, + "Remove block body braces": { + "category": "Message", + "code": 95066 + }, + "Replace braces with parentheses": { + "category": "Message", + "code": 95067 + }, + "Wrap this block with parentheses": { + "category": "Message", + "code": 95068 + }, + "Surmise all return value": { + "category": "Message", + "code": 95069 } } diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts new file mode 100644 index 0000000000000..e3db9ccd49cd2 --- /dev/null +++ b/src/services/codefixes/returnValueSurmise.ts @@ -0,0 +1,50 @@ +/* @internal */ +namespace ts.codefix { + const fixId = "returnValueSurmise"; + const errorCodes = [ + Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code, + Diagnostics.Type_0_is_not_assignable_to_type_1.code, + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code + ]; + registerCodeFix({ + errorCodes, + getCodeActions: context => { + const { host, sourceFile, span: { start } } = context; + return packageName === undefined ? [] + : [createCodeFixAction(fixId, /*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))]; + }, + fixIds: [fixId], + getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => { + const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start, diag.code); + if (pkg) { + commands.push(getCommand(diag.file.fileName, pkg)); + } + }), + }); + + interface Info { + + } + + function getInfo (checker: TypeChecker, sourceFile: SourceFile, position: number): Info | undefined { + const node = getTokenAtPosition(sourceFile, position); + if (!node.parent) return undefined; + + if (isTypeNode(node) && isFunctionLikeDeclaration(node.parent)) { + + } + else if (isDeclarationName(node) && isVariableLike(node.parent)) { + + } + else { + Debug.fail('unknow pattern'); + } + + + const functionLikeDeclaration = cast(node.parent, isFunctionLike); + Debug.assert(functionLikeDeclaration.type === node); + + const returnType = checker.getTypeFromTypeNode(cast(node, isTypeNode)); + + } +} diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 355a4d302c0e8..f5b047752440f 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -51,6 +51,7 @@ "codefixes/fixClassIncorrectlyImplementsInterface.ts", "codefixes/importFixes.ts", "codefixes/fixSpelling.ts", + "codefixes/returnValueSurmise.ts", "codefixes/fixAddMissingMember.ts", "codefixes/fixCannotFindModule.ts", "codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", From 767122129ec3571ea6d7126e8e6c7cb43303cddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Tue, 14 Aug 2018 11:44:13 +0800 Subject: [PATCH 02/20] add surmise for return type --- src/compiler/checker.ts | 1 + src/compiler/types.ts | 1 + src/services/codefixes/returnValueSurmise.ts | 255 ++++++++++++++---- .../fourslash/codeFixSurmiseReturnValue1.ts | 11 + .../fourslash/codeFixSurmiseReturnValue10.ts | 9 + .../fourslash/codeFixSurmiseReturnValue2.ts | 15 ++ .../fourslash/codeFixSurmiseReturnValue3.ts | 15 ++ .../fourslash/codeFixSurmiseReturnValue4.ts | 7 + .../fourslash/codeFixSurmiseReturnValue5.ts | 7 + .../fourslash/codeFixSurmiseReturnValue6.ts | 11 + .../fourslash/codeFixSurmiseReturnValue7.ts | 10 + .../fourslash/codeFixSurmiseReturnValue8.ts | 10 + .../fourslash/codeFixSurmiseReturnValue9.ts | 9 + 13 files changed, 311 insertions(+), 50 deletions(-) create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue1.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue10.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue2.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue3.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue4.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue5.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue6.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue7.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue8.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue9.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 649979e412084..a62af2fc229a4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -293,6 +293,7 @@ namespace ts { isArrayLikeType, isTypeInvalidDueToUnionDiscriminant, getAllPossiblePropertiesOfTypes, + isTypeAssignableTo, getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type), getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), getSuggestionForNonexistentExport: (node, target) => getSuggestionForNonexistentExport(node, target), diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 06867a94c17cb..09690da3ec2b1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3072,6 +3072,7 @@ namespace ts { * e.g. it specifies `kind: "a"` and obj has `kind: "b"`. */ /* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression): boolean; + /* @internal */ isTypeAssignableTo(type1: Type, type2: Type): boolean; /** * For a union, will include a property if it's defined in *any* of the member types. * So for `{ a } | { b }`, this will include both `a` and `b`. diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts index e3db9ccd49cd2..01680ccce7d9e 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueSurmise.ts @@ -1,50 +1,205 @@ -/* @internal */ -namespace ts.codefix { - const fixId = "returnValueSurmise"; - const errorCodes = [ - Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code, - Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code - ]; - registerCodeFix({ - errorCodes, - getCodeActions: context => { - const { host, sourceFile, span: { start } } = context; - return packageName === undefined ? [] - : [createCodeFixAction(fixId, /*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))]; - }, - fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => { - const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start, diag.code); - if (pkg) { - commands.push(getCommand(diag.file.fileName, pkg)); - } - }), - }); - - interface Info { - - } - - function getInfo (checker: TypeChecker, sourceFile: SourceFile, position: number): Info | undefined { - const node = getTokenAtPosition(sourceFile, position); - if (!node.parent) return undefined; - - if (isTypeNode(node) && isFunctionLikeDeclaration(node.parent)) { - - } - else if (isDeclarationName(node) && isVariableLike(node.parent)) { - - } - else { - Debug.fail('unknow pattern'); - } - - - const functionLikeDeclaration = cast(node.parent, isFunctionLike); - Debug.assert(functionLikeDeclaration.type === node); - - const returnType = checker.getTypeFromTypeNode(cast(node, isTypeNode)); - - } -} +/* @internal */ +namespace ts.codefix { + const fixId = "returnValueSurmise"; + const fixIdAddReturnStatement = "fixAddReturnStatement"; + const fixIdRemoveBlockBodyBrace = "fixRemoveBlockBodyBrace"; + const fixIdReplaceBraceWithParen = "fixReplaceBraceWithParen"; + const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen"; + const errorCodes = [ + Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code, + Diagnostics.Type_0_is_not_assignable_to_type_1.code, + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code + ]; + + enum FixKind { + MissingReturnStatement, + MissingParentheses + } + + interface Info { + declaration: FunctionLikeDeclaration; + fixKind: FixKind; + } + + registerCodeFix({ + errorCodes, + fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdReplaceBraceWithParen, fixIdWrapTheBlockWithParen], + getCodeActions: context => { + const { program, sourceFile, span: { start } } = context; + const info = getInfo(program.getTypeChecker(), sourceFile, start); + if (!info) return undefined; + + if (info.fixKind === FixKind.MissingReturnStatement) { + return [ + getActionForfixAddReturnStatement(context, info.declaration), + getActionForfixRemoveBlockBodyBrace(context, info.declaration), + getActionForfixReplaceBraceWithParen(context, info.declaration) + ]; + } + else { + return [getActionForfixWrapTheBlockWithParen(context, info.declaration)]; + } + }, + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start); + if (!info) return undefined; + + switch (context.fixId) { + case fixIdAddReturnStatement: + addReturnStatement(changes, diag.file, info.declaration); + break; + case fixIdRemoveBlockBodyBrace: + removeBlockBodyBrace(changes, diag.file, info.declaration, /* withParen */ false); + break; + case fixIdReplaceBraceWithParen: + removeBlockBodyBrace(changes, diag.file, info.declaration, /* withParen */ true); + break; + case fixIdWrapTheBlockWithParen: + wrapBlockWithParen(changes, diag.file, info.declaration); + break; + default: + Debug.fail(JSON.stringify(context.fixId)); + } + }), + }); + + function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration { + switch (declaration.kind) { + case SyntaxKind.FunctionDeclaration: + return createFunctionDeclaration(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.MethodDeclaration: + return createMethod(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.questionToken, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.GetAccessor: + return createGetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, declaration.type, body); + case SyntaxKind.SetAccessor: + return createSetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, body); + case SyntaxKind.Constructor: + return createConstructor(declaration.decorators, declaration.modifiers, declaration.parameters, body); + case SyntaxKind.FunctionExpression: + return createFunctionExpression(declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.ArrowFunction: + return createArrowFunction(declaration.modifiers, declaration.typeParameters, declaration.parameters, declaration.type, declaration.equalsGreaterThanToken, body); + } + } + + function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type): Info | undefined { + if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; + + const firstStatement = first(declaration.body.statements); + if (isExpressionStatement(firstStatement)) { + const maybeFunction = updateFunctionLikeBody(declaration, createBlock([createReturn(firstStatement.expression)])); + const maybeType = checker.getTypeAtLocation(maybeFunction); + if (checker.isTypeAssignableTo(maybeType, expectType)) { + return { + declaration, + fixKind: FixKind.MissingReturnStatement + }; + } + } + else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { + const maybeFunction = updateFunctionLikeBody(declaration, createBlock([createReturn( + createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]) + )])); + const maybeType = checker.getTypeAtLocation(maybeFunction); + if (checker.isTypeAssignableTo(maybeType, expectType)) { + return { + declaration, + fixKind: FixKind.MissingParentheses + }; + } + } + + return undefined; + } + + function getFixInfoFromTypeAnnotation(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type): Info | undefined { + if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; + + const firstStatement = first(declaration.body.statements); + if (isExpressionStatement(firstStatement)) { + const actualType = checker.getTypeAtLocation(firstStatement.expression); + if (checker.isTypeAssignableTo(actualType, expectType)) { + return { + declaration, + fixKind: FixKind.MissingReturnStatement + }; + } + } + else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { + const node = createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); + const type = checker.getTypeAtLocation(node); + if (checker.isTypeAssignableTo(type, expectType)) { + return { + declaration, + fixKind: FixKind.MissingParentheses + }; + } + } + + return undefined; + } + + function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number): Info | undefined { + const node = getTokenAtPosition(sourceFile, position); + if (!node.parent) return undefined; + + const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); + if (declaration) { + if (declaration.body && declaration.type && rangeContainsRange(declaration.type, node)) { + // check by type annotation + return getFixInfoFromTypeAnnotation(checker, declaration, checker.getTypeFromTypeNode(declaration.type)); + } + else if (isCallExpression(declaration.parent) && declaration.body) { + const pos = declaration.parent.arguments.indexOf(declaration); + const type = checker.getContextualTypeForArgumentAtIndex(declaration.parent, pos); + if (!type) return undefined; + return getFixInfo(checker, declaration, type); + } + } + else if (isDeclarationName(node) && isVariableDeclaration(node.parent) && node.parent.initializer && node.parent.type) { + const initializer = skipParentheses(node.parent.initializer); + if (!isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; + return getFixInfo(checker, initializer, checker.getTypeFromTypeNode(node.parent.type)); + } + Debug.fail("unknow pattern"); + } + + function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration) { + const body = cast(declaration.body, isBlock); + const firstStatement = cast(first(body.statements), isExpressionStatement); + changes.replaceNode(sourceFile, firstStatement, createReturn(firstStatement.expression)); + } + + function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, withParen: boolean) { + const body = cast(declaration.body, isBlock); + const expression = cast(first(body.statements), isExpressionStatement).expression; + changes.replaceNode(sourceFile, body, withParen ? createParen(expression) : expression); + } + + function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration) { + const body = cast(declaration.body, isBlock); + const labeledStatement = cast(first(body.statements), isLabeledStatement); + const expression = cast(labeledStatement.statement, isExpressionStatement).expression; + changes.replaceNode(sourceFile, body, createParen(createObjectLiteral([createPropertyAssignment(labeledStatement.label, expression)]))); + } + + function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration) { + const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration)); + return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Surmise_all_return_value); + } + + function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: FunctionLikeDeclaration) { + const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, /* withParen */ false)); + return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Surmise_all_return_value); + } + + function getActionForfixReplaceBraceWithParen(context: CodeFixContext, declaration: FunctionLikeDeclaration) { + const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, /* withParen */ true)); + return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Surmise_all_return_value); + } + + function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: FunctionLikeDeclaration) { + const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration)); + return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Surmise_all_return_value); + } +} diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts new file mode 100644 index 0000000000000..e80ba8fd2ab3e --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts @@ -0,0 +1,11 @@ +/// + +//// function Foo (): number { +//// 1 +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts new file mode 100644 index 0000000000000..c8a94d90a7d6d --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts @@ -0,0 +1,9 @@ +/// + +//// const a: ((() => number) | (() => undefined)) = () => { 1 } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts new file mode 100644 index 0000000000000..b7e1086b08846 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts @@ -0,0 +1,15 @@ +/// + +//// interface A { +//// foo: number +//// } + +//// function Foo (): A { +//// ({ foo: 1 }) +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts new file mode 100644 index 0000000000000..0e3a845c5ec64 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts @@ -0,0 +1,15 @@ +/// + +//// interface A { +//// foo: number +//// } + +//// function Foo (): A | number { +//// 1 +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue4.ts new file mode 100644 index 0000000000000..e1270bee3f361 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue4.ts @@ -0,0 +1,7 @@ +/// + +//// function Foo (): any { +//// 1 +//// } + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue5.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue5.ts new file mode 100644 index 0000000000000..de457636368eb --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue5.ts @@ -0,0 +1,7 @@ +/// + +//// function Foo (): void { +//// undefined +//// } + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts new file mode 100644 index 0000000000000..deb5170c5f803 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts @@ -0,0 +1,11 @@ +/// + +//// function Foo (): undefined { +//// undefined +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts new file mode 100644 index 0000000000000..5a40e0a7f66dd --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts @@ -0,0 +1,10 @@ +/// + +//// function Foo (a: () => number) { a() } +//// Foo(() => { 1 }) + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts new file mode 100644 index 0000000000000..8ebc2500cabcc --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts @@ -0,0 +1,10 @@ +/// + +//// function Foo (a: (() => number) | (() => undefined) ) { a() } +//// Foo(() => { 1 }) + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts new file mode 100644 index 0000000000000..8abf79d631f7b --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts @@ -0,0 +1,9 @@ +/// + +//// const a: () => number = () => { 1 } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); From 0b1e6cc6ea15df4a599d317775bfa9a52885fb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Tue, 14 Aug 2018 18:50:16 +0800 Subject: [PATCH 03/20] add support for more case --- src/services/codefixes/returnValueSurmise.ts | 114 +++++++++--------- .../fourslash/codeFixSurmiseReturnValue11.ts | 15 +++ .../fourslash/codeFixSurmiseReturnValue12.ts | 16 +++ .../fourslash/codeFixSurmiseReturnValue13.ts | 15 +++ .../fourslash/codeFixSurmiseReturnValue14.ts | 13 ++ .../fourslash/codeFixSurmiseReturnValue15.ts | 12 ++ 6 files changed, 129 insertions(+), 56 deletions(-) create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue11.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue12.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue13.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue14.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue15.ts diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts index 01680ccce7d9e..75d9f82c982a0 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueSurmise.ts @@ -16,11 +16,18 @@ namespace ts.codefix { MissingParentheses } - interface Info { + interface MissingReturnInfo { + kind: FixKind.MissingReturnStatement; declaration: FunctionLikeDeclaration; - fixKind: FixKind; } + interface MissingParenthesesInfo { + kind: FixKind.MissingParentheses; + declaration: ArrowFunction; + } + + type Info = MissingReturnInfo | MissingParenthesesInfo; + registerCodeFix({ errorCodes, fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdReplaceBraceWithParen, fixIdWrapTheBlockWithParen], @@ -29,7 +36,7 @@ namespace ts.codefix { const info = getInfo(program.getTypeChecker(), sourceFile, start); if (!info) return undefined; - if (info.fixKind === FixKind.MissingReturnStatement) { + if (info.kind === FixKind.MissingReturnStatement) { return [ getActionForfixAddReturnStatement(context, info.declaration), getActionForfixRemoveBlockBodyBrace(context, info.declaration), @@ -55,7 +62,7 @@ namespace ts.codefix { removeBlockBodyBrace(changes, diag.file, info.declaration, /* withParen */ true); break; case fixIdWrapTheBlockWithParen: - wrapBlockWithParen(changes, diag.file, info.declaration); + wrapBlockWithParen(changes, diag.file, info.declaration); break; default: Debug.fail(JSON.stringify(context.fixId)); @@ -82,61 +89,43 @@ namespace ts.codefix { } } - function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type): Info | undefined { + function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type, isFunctionType: boolean): Info | undefined { if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; const firstStatement = first(declaration.body.statements); - if (isExpressionStatement(firstStatement)) { - const maybeFunction = updateFunctionLikeBody(declaration, createBlock([createReturn(firstStatement.expression)])); - const maybeType = checker.getTypeAtLocation(maybeFunction); - if (checker.isTypeAssignableTo(maybeType, expectType)) { + if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, firstStatement.expression, expectType, isFunctionType)) { + return { + declaration, + kind: FixKind.MissingReturnStatement + }; + } + else if (isArrowFunction(declaration) && isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { + const node = createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); + if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { return { declaration, - fixKind: FixKind.MissingReturnStatement + kind: FixKind.MissingParentheses }; } } - else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { - const maybeFunction = updateFunctionLikeBody(declaration, createBlock([createReturn( - createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]) - )])); - const maybeType = checker.getTypeAtLocation(maybeFunction); - if (checker.isTypeAssignableTo(maybeType, expectType)) { - return { - declaration, - fixKind: FixKind.MissingParentheses - }; + else if (isBlock(firstStatement) && length(firstStatement.statements) === 1) { + const firstBlockStatement = first(firstStatement.statements); + if (isLabeledStatement(firstBlockStatement) && isExpressionStatement(firstBlockStatement.statement)) { + const node = createObjectLiteral([createPropertyAssignment(firstBlockStatement.label, firstBlockStatement.statement.expression)]); + if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { + return { + declaration, + kind: FixKind.MissingReturnStatement + }; + } } } return undefined; } - function getFixInfoFromTypeAnnotation(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type): Info | undefined { - if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; - - const firstStatement = first(declaration.body.statements); - if (isExpressionStatement(firstStatement)) { - const actualType = checker.getTypeAtLocation(firstStatement.expression); - if (checker.isTypeAssignableTo(actualType, expectType)) { - return { - declaration, - fixKind: FixKind.MissingReturnStatement - }; - } - } - else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { - const node = createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); - const type = checker.getTypeAtLocation(node); - if (checker.isTypeAssignableTo(type, expectType)) { - return { - declaration, - fixKind: FixKind.MissingParentheses - }; - } - } - - return undefined; + function checkFixedAssignableTo (checker: TypeChecker, declaration: FunctionLikeDeclaration, expr: Expression, type: Type, isFunctionType: boolean) { + return checker.isTypeAssignableTo(checker.getTypeAtLocation(isFunctionType ? updateFunctionLikeBody(declaration, createBlock([createReturn(expr)])) : expr), type); } function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number): Info | undefined { @@ -146,41 +135,54 @@ namespace ts.codefix { const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); if (declaration) { if (declaration.body && declaration.type && rangeContainsRange(declaration.type, node)) { - // check by type annotation - return getFixInfoFromTypeAnnotation(checker, declaration, checker.getTypeFromTypeNode(declaration.type)); + return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /* isFunctionType */ false); } else if (isCallExpression(declaration.parent) && declaration.body) { const pos = declaration.parent.arguments.indexOf(declaration); const type = checker.getContextualTypeForArgumentAtIndex(declaration.parent, pos); if (!type) return undefined; - return getFixInfo(checker, declaration, type); + return getFixInfo(checker, declaration, type, /* isFunctionType */ true); } } else if (isDeclarationName(node) && isVariableDeclaration(node.parent) && node.parent.initializer && node.parent.type) { const initializer = skipParentheses(node.parent.initializer); if (!isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; - return getFixInfo(checker, initializer, checker.getTypeFromTypeNode(node.parent.type)); + return getFixInfo(checker, initializer, checker.getTypeFromTypeNode(node.parent.type), /* isFunctionType */ true); + } + return Debug.fail("unknow pattern"); + } + + function getReturnExpression (stmt: Statement) { + if (isExpressionStatement(stmt)) { + return stmt.expression; } - Debug.fail("unknow pattern"); + else if (isBlock(stmt) && length(stmt.statements) === 1) { + const block = first(stmt.statements); + if (isLabeledStatement(block) && isExpressionStatement(block.statement)) { + return block.statement.expression; + } + } + + return Debug.fail("unknow statement"); } function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration) { const body = cast(declaration.body, isBlock); - const firstStatement = cast(first(body.statements), isExpressionStatement); - changes.replaceNode(sourceFile, firstStatement, createReturn(firstStatement.expression)); + const firstStatement = first(body.statements); + changes.replaceNode(sourceFile, firstStatement, createReturn(getReturnExpression(firstStatement))); } function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, withParen: boolean) { const body = cast(declaration.body, isBlock); - const expression = cast(first(body.statements), isExpressionStatement).expression; + const expression = getReturnExpression(first(body.statements)); changes.replaceNode(sourceFile, body, withParen ? createParen(expression) : expression); } - function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration) { + function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction) { const body = cast(declaration.body, isBlock); const labeledStatement = cast(first(body.statements), isLabeledStatement); const expression = cast(labeledStatement.statement, isExpressionStatement).expression; - changes.replaceNode(sourceFile, body, createParen(createObjectLiteral([createPropertyAssignment(labeledStatement.label, expression)]))); + changes.replaceNode(sourceFile, declaration.body, createParen(createObjectLiteral([createPropertyAssignment(labeledStatement.label, expression)]))); } function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration) { @@ -198,7 +200,7 @@ namespace ts.codefix { return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Surmise_all_return_value); } - function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: FunctionLikeDeclaration) { + function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction) { const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration)); return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Surmise_all_return_value); } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts new file mode 100644 index 0000000000000..2e06f9958ad22 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts @@ -0,0 +1,15 @@ +/// +//// interface A { +//// bar: string +//// } +//// +//// function Foo (): A { +//// { bar: '123' } +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts new file mode 100644 index 0000000000000..8672eb7882fd0 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts @@ -0,0 +1,16 @@ +/// +//// interface A { +//// bar: string +//// } +//// +//// function Foo (a: () => A) { a() } +//// Foo(() => { +//// { bar: '123' } +//// }) + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts new file mode 100644 index 0000000000000..d1f2f275b41bf --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts @@ -0,0 +1,15 @@ +/// +//// interface A { +//// bar: string +//// } +//// +//// const a: () => A = () => { +//// { bar: '1' } +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts new file mode 100644 index 0000000000000..59091741c13d8 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts @@ -0,0 +1,13 @@ +/// +//// interface A { +//// bar: string +//// } +//// +//// const a: () => A = () => { +//// bar: '1' +//// } + +verify.codeFixAvailable([ + { description: 'Wrap this block with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts new file mode 100644 index 0000000000000..8e2970fea2c0e --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts @@ -0,0 +1,12 @@ +/// +//// interface A { +//// bar: string +//// } +//// +//// function Foo (a: () => A) { a() } +//// Foo(() => { bar: '1' }) + +verify.codeFixAvailable([ + { description: 'Wrap this block with parentheses' }, + { description: 'Remove unused label' }, +]); From 1f9b9c09f4ab269f09afe28bf8c9031fab3d6f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Thu, 16 Aug 2018 18:22:39 +0800 Subject: [PATCH 04/20] add more test case --- src/services/codefixes/returnValueSurmise.ts | 102 +++++++--------- .../addOrRemoveBracesToArrowFunction.ts | 4 - src/services/utilities.ts | 5 + .../fourslash/codeFixSurmiseReturnValue1.ts | 2 - .../fourslash/codeFixSurmiseReturnValue11.ts | 2 - .../fourslash/codeFixSurmiseReturnValue13.ts | 4 + .../fourslash/codeFixSurmiseReturnValue16.ts | 13 ++ .../fourslash/codeFixSurmiseReturnValue17.ts | 14 +++ .../fourslash/codeFixSurmiseReturnValue2.ts | 2 - .../fourslash/codeFixSurmiseReturnValue3.ts | 2 - .../fourslash/codeFixSurmiseReturnValue6.ts | 2 - .../codeFixSurmiseReturnValue_all1.ts | 115 ++++++++++++++++++ .../codeFixSurmiseReturnValue_all2.ts | 95 +++++++++++++++ .../codeFixSurmiseReturnValue_all3.ts | 95 +++++++++++++++ .../codeFixSurmiseReturnValue_all4.ts | 95 +++++++++++++++ 15 files changed, 483 insertions(+), 69 deletions(-) create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue16.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue17.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts index 75d9f82c982a0..791e9c8ff6f92 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueSurmise.ts @@ -19,14 +19,16 @@ namespace ts.codefix { interface MissingReturnInfo { kind: FixKind.MissingReturnStatement; declaration: FunctionLikeDeclaration; + expression: Expression; } - interface MissingParenthesesInfo { + interface MissingParenInfo { kind: FixKind.MissingParentheses; declaration: ArrowFunction; + expression: Expression; } - type Info = MissingReturnInfo | MissingParenthesesInfo; + type Info = MissingReturnInfo | MissingParenInfo; registerCodeFix({ errorCodes, @@ -37,14 +39,15 @@ namespace ts.codefix { if (!info) return undefined; if (info.kind === FixKind.MissingReturnStatement) { - return [ - getActionForfixAddReturnStatement(context, info.declaration), - getActionForfixRemoveBlockBodyBrace(context, info.declaration), - getActionForfixReplaceBraceWithParen(context, info.declaration) - ]; + return concatenate( + [getActionForfixAddReturnStatement(context, info.declaration, info.expression)], + isArrowFunction(info.declaration) ? [ + getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression), + getActionForfixReplaceBraceWithParen(context, info.declaration, info.expression) + ] : undefined); } else { - return [getActionForfixWrapTheBlockWithParen(context, info.declaration)]; + return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)]; } }, getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { @@ -53,16 +56,19 @@ namespace ts.codefix { switch (context.fixId) { case fixIdAddReturnStatement: - addReturnStatement(changes, diag.file, info.declaration); + addReturnStatement(changes, diag.file, info.declaration, info.expression); break; case fixIdRemoveBlockBodyBrace: - removeBlockBodyBrace(changes, diag.file, info.declaration, /* withParen */ false); + if (!isArrowFunction(info.declaration)) return undefined; + removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, /* withParen */ false); break; case fixIdReplaceBraceWithParen: - removeBlockBodyBrace(changes, diag.file, info.declaration, /* withParen */ true); + if (!isArrowFunction(info.declaration)) return undefined; + removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, /* withParen */ true); break; case fixIdWrapTheBlockWithParen: - wrapBlockWithParen(changes, diag.file, info.declaration); + if (!isArrowFunction(info.declaration)) return undefined; + wrapBlockWithParen(changes, diag.file, info.declaration, info.expression); break; default: Debug.fail(JSON.stringify(context.fixId)); @@ -96,16 +102,22 @@ namespace ts.codefix { if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, firstStatement.expression, expectType, isFunctionType)) { return { declaration, - kind: FixKind.MissingReturnStatement + kind: FixKind.MissingReturnStatement, + expression: firstStatement.expression }; } - else if (isArrowFunction(declaration) && isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { + else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { const node = createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { - return { + return isArrowFunction(declaration) ? { declaration, - kind: FixKind.MissingParentheses - }; + kind: FixKind.MissingParentheses, + expression: node + } : { + declaration, + kind: FixKind.MissingReturnStatement, + expression: node + }; } } else if (isBlock(firstStatement) && length(firstStatement.statements) === 1) { @@ -115,7 +127,8 @@ namespace ts.codefix { if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { return { declaration, - kind: FixKind.MissingReturnStatement + kind: FixKind.MissingReturnStatement, + expression: node }; } } @@ -124,7 +137,7 @@ namespace ts.codefix { return undefined; } - function checkFixedAssignableTo (checker: TypeChecker, declaration: FunctionLikeDeclaration, expr: Expression, type: Type, isFunctionType: boolean) { + function checkFixedAssignableTo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expr: Expression, type: Type, isFunctionType: boolean) { return checker.isTypeAssignableTo(checker.getTypeAtLocation(isFunctionType ? updateFunctionLikeBody(declaration, createBlock([createReturn(expr)])) : expr), type); } @@ -149,59 +162,38 @@ namespace ts.codefix { if (!isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; return getFixInfo(checker, initializer, checker.getTypeFromTypeNode(node.parent.type), /* isFunctionType */ true); } - return Debug.fail("unknow pattern"); - } - - function getReturnExpression (stmt: Statement) { - if (isExpressionStatement(stmt)) { - return stmt.expression; - } - else if (isBlock(stmt) && length(stmt.statements) === 1) { - const block = first(stmt.statements); - if (isLabeledStatement(block) && isExpressionStatement(block.statement)) { - return block.statement.expression; - } - } - - return Debug.fail("unknow statement"); + return undefined; } - function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration) { - const body = cast(declaration.body, isBlock); - const firstStatement = first(body.statements); - changes.replaceNode(sourceFile, firstStatement, createReturn(getReturnExpression(firstStatement))); + function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, expression: Expression) { + changes.replaceNode(sourceFile, declaration.body!, createBlock([createReturn(expression)])); } - function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, withParen: boolean) { - const body = cast(declaration.body, isBlock); - const expression = getReturnExpression(first(body.statements)); - changes.replaceNode(sourceFile, body, withParen ? createParen(expression) : expression); + function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, withParen: boolean) { + changes.replaceNode(sourceFile, declaration.body, (withParen || needsParentheses(expression)) ? createParen(expression) : expression); } - function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction) { - const body = cast(declaration.body, isBlock); - const labeledStatement = cast(first(body.statements), isLabeledStatement); - const expression = cast(labeledStatement.statement, isExpressionStatement).expression; - changes.replaceNode(sourceFile, declaration.body, createParen(createObjectLiteral([createPropertyAssignment(labeledStatement.label, expression)]))); + function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression) { + changes.replaceNode(sourceFile, declaration.body, createParen(expression)); } - function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration) { - const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration)); + function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration, expression: Expression) { + const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration, expression)); return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Surmise_all_return_value); } - function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: FunctionLikeDeclaration) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, /* withParen */ false)); + function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { + const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ false)); return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Surmise_all_return_value); } - function getActionForfixReplaceBraceWithParen(context: CodeFixContext, declaration: FunctionLikeDeclaration) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, /* withParen */ true)); + function getActionForfixReplaceBraceWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { + const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ true)); return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Surmise_all_return_value); } - function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction) { - const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration)); + function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { + const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Surmise_all_return_value); } } diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index 57e7dbd97a76c..789dab59dd396 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -64,10 +64,6 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { return { renameFilename: undefined, renameLocation: undefined, edits }; } - function needsParentheses(expression: Expression) { - return isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.CommaToken || isObjectLiteralExpression(expression); - } - function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number): Info | undefined { const node = getTokenAtPosition(file, startPosition); const func = getContainingFunction(node); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e8d9c8a904793..9e9621c2f6fa8 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1783,4 +1783,9 @@ namespace ts { if (idx === -1) idx = change.indexOf('"' + name); return idx === -1 ? -1 : idx + 1; } + + /* @internal */ + export function needsParentheses(expression: Expression) { + return isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.CommaToken || isObjectLiteralExpression(expression); + } } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts index e80ba8fd2ab3e..4dc5bdfc68386 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts @@ -6,6 +6,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts index 2e06f9958ad22..a57c05134959c 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts @@ -9,7 +9,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts index d1f2f275b41bf..37360499d9e5e 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts @@ -13,3 +13,7 @@ verify.codeFixAvailable([ { description: 'Replace braces with parentheses' }, { description: 'Remove unused label' }, ]); + +interface A { + bar: string +} diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts new file mode 100644 index 0000000000000..5292a10f776e7 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts @@ -0,0 +1,13 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function Foo (a: () => A) { a() } +//// Foo(() => { bar: '1' }) + +verify.codeFixAvailable([ + { description: 'Wrap this block with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue17.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue17.ts new file mode 100644 index 0000000000000..2572b478e1756 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue17.ts @@ -0,0 +1,14 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function Foo (): A { +//// bar: '123' +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts index b7e1086b08846..9d361067c4ca5 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts @@ -10,6 +10,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts index 0e3a845c5ec64..364da21f42dfc 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts @@ -10,6 +10,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts index deb5170c5f803..693145f8c61b8 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts @@ -6,6 +6,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts new file mode 100644 index 0000000000000..404015144937f --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -0,0 +1,115 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function foo1 (_a: () => number ) { } +//// foo1(() => { +//// 1 +//// }) +//// function foo2 (_a: () => A) { } +//// foo2(() => { +//// { bar: '1' } +//// }) +//// foo2(() => { +//// bar: '1' +//// }) +//// function foo3 (_a: () => A | number) { } +//// foo3(() => { +//// 1 +//// }) +//// foo3(() => { +//// bar: '1' +//// }) +//// +//// function bar1 (): number { +//// 1 +//// } +//// function bar2 (): A { +//// { bar: '1' } +//// } +//// function bar3 (): A { +//// bar: '1' +//// } +//// function bar4 (): A | number { +//// 1 +//// } +//// function bar5(): A | number { +//// bar: '1' +//// } +// +//// const baz1: () => number = () => { +//// 1 +//// } +//// const baz2: () => A = () => { +//// { bar: '1' } +//// } +//// const baz3: () => A = () => { +//// bar: '1' +//// } +//// const baz4: ((() => number) | (() => A)) = () => { +//// 1 +//// } +//// const baz5: ((() => number) | (() => A)) = () => { +//// bar: '1' +//// } + +verify.codeFixAll({ + fixId: "fixAddReturnStatement", + fixAllDescription: "Surmise all return value", + newFileContent: +`interface A { + bar: string +} + +function foo1 (_a: () => number ) { } +foo1(() => { + return 1; +}) +function foo2 (_a: () => A) { } +foo2(() => { + return { bar: '1' }; +}) +foo2(() => { + return { bar: '1' }; +}) +function foo3 (_a: () => A | number) { } +foo3(() => { + return 1; +}) +foo3(() => { + return { bar: '1' }; +}) + +function bar1 (): number { + return 1; +} +function bar2 (): A { + return { bar: '1' }; +} +function bar3 (): A { + return { bar: '1' }; +} +function bar4 (): A | number { + return 1; +} +function bar5(): A | number { + return { bar: '1' }; +} +const baz1: () => number = () => { + return 1; +} +const baz2: () => A = () => { + return { bar: '1' }; +} +const baz3: () => A = () => { + return { bar: '1' }; +} +const baz4: ((() => number) | (() => A)) = () => { + return 1; +} +const baz5: ((() => number) | (() => A)) = () => { + return { bar: '1' }; +}`, +}); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts new file mode 100644 index 0000000000000..5061018f1feb0 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -0,0 +1,95 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function foo1 (_a: () => number ) { } +//// foo1(() => { +//// 1 +//// }) +//// function foo2 (_a: () => A) { } +//// foo2(() => { +//// { bar: '1' } +//// }) +//// foo2(() => { +//// bar: '1' +//// }) +//// function foo3 (_a: () => A | number) { } +//// foo3(() => { +//// 1 +//// }) +//// foo3(() => { +//// bar: '1' +//// }) +//// +//// function bar1 (): number { +//// 1 +//// } +//// function bar2 (): A { +//// { bar: '1' } +//// } +//// function bar3 (): A { +//// bar: '1' +//// } +//// function bar4 (): A | number { +//// 1 +//// } +//// function bar5(): A | number { +//// bar: '1' +//// } +// +//// const baz1: () => number = () => { +//// 1 +//// } +//// const baz2: () => A = () => { +//// { bar: '1' } +//// } +//// const baz3: () => A = () => { +//// bar: '1' +//// } +//// const baz4: ((() => number) | (() => A)) = () => { +//// 1 +//// } +//// const baz5: ((() => number) | (() => A)) = () => { +//// bar: '1' +//// } + +verify.codeFixAll({ + fixId: "fixRemoveBlockBodyBrace", + fixAllDescription: "Surmise all return value", + newFileContent: +`interface A { + bar: string +} + +function foo1 (_a: () => number ) { } +foo1(() => 1) +function foo2 (_a: () => A) { } +foo2(() => ({ bar: '1' })) +foo2(() => ({ bar: '1' })) +function foo3 (_a: () => A | number) { } +foo3(() => 1) +foo3(() => ({ bar: '1' })) + +function bar1 (): number { + 1 +} +function bar2 (): A { + { bar: '1' } +} +function bar3 (): A { + bar: '1' +} +function bar4 (): A | number { + 1 +} +function bar5(): A | number { + bar: '1' +} +const baz1: () => number = () => 1 +const baz2: () => A = () => ({ bar: '1' }) +const baz3: () => A = () => ({ bar: '1' }) +const baz4: ((() => number) | (() => A)) = () => 1 +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +}); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts new file mode 100644 index 0000000000000..31d71cda5439c --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -0,0 +1,95 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function foo1 (_a: () => number ) { } +//// foo1(() => { +//// 1 +//// }) +//// function foo2 (_a: () => A) { } +//// foo2(() => { +//// { bar: '1' } +//// }) +//// foo2(() => { +//// bar: '1' +//// }) +//// function foo3 (_a: () => A | number) { } +//// foo3(() => { +//// 1 +//// }) +//// foo3(() => { +//// bar: '1' +//// }) +//// +//// function bar1 (): number { +//// 1 +//// } +//// function bar2 (): A { +//// { bar: '1' } +//// } +//// function bar3 (): A { +//// bar: '1' +//// } +//// function bar4 (): A | number { +//// 1 +//// } +//// function bar5(): A | number { +//// bar: '1' +//// } +// +//// const baz1: () => number = () => { +//// 1 +//// } +//// const baz2: () => A = () => { +//// { bar: '1' } +//// } +//// const baz3: () => A = () => { +//// bar: '1' +//// } +//// const baz4: ((() => number) | (() => A)) = () => { +//// 1 +//// } +//// const baz5: ((() => number) | (() => A)) = () => { +//// bar: '1' +//// } + +verify.codeFixAll({ + fixId: "fixReplaceBraceWithParen", + fixAllDescription: "Surmise all return value", + newFileContent: +`interface A { + bar: string +} + +function foo1 (_a: () => number ) { } +foo1(() => (1)) +function foo2 (_a: () => A) { } +foo2(() => ({ bar: '1' })) +foo2(() => ({ bar: '1' })) +function foo3 (_a: () => A | number) { } +foo3(() => (1)) +foo3(() => ({ bar: '1' })) + +function bar1 (): number { + 1 +} +function bar2 (): A { + { bar: '1' } +} +function bar3 (): A { + bar: '1' +} +function bar4 (): A | number { + 1 +} +function bar5(): A | number { + bar: '1' +} +const baz1: () => number = () => (1) +const baz2: () => A = () => ({ bar: '1' }) +const baz3: () => A = () => ({ bar: '1' }) +const baz4: ((() => number) | (() => A)) = () => (1) +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +}); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts new file mode 100644 index 0000000000000..760e422580338 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts @@ -0,0 +1,95 @@ +/// + +//// interface A { +//// bar: string +//// } +//// +//// function foo1 (_a: () => number ) { } +//// foo1(() => { +//// 1 +//// }) +//// function foo2 (_a: () => A) { } +//// foo2(() => { +//// { bar: '1' } +//// }) +//// foo2(() => { +//// bar: '1' +//// }) +//// function foo3 (_a: () => A | number) { } +//// foo3(() => { +//// 1 +//// }) +//// foo3(() => { +//// bar: '1' +//// }) +//// +//// function bar1 (): number { +//// 1 +//// } +//// function bar2 (): A { +//// { bar: '1' } +//// } +//// function bar3 (): A { +//// bar: '1' +//// } +//// function bar4 (): A | number { +//// 1 +//// } +//// function bar5(): A | number { +//// bar: '1' +//// } +// +//// const baz1: () => number = () => { +//// 1 +//// } +//// const baz2: () => A = () => { +//// { bar: '1' } +//// } +//// const baz3: () => A = () => { +//// bar: '1' +//// } +//// const baz4: ((() => number) | (() => A)) = () => { +//// 1 +//// } +//// const baz5: ((() => number) | (() => A)) = () => { +//// bar: '1' +//// } + +verify.codeFixAll({ + fixId: "fixWrapTheBlockWithParen", + fixAllDescription: "Surmise all return value", + newFileContent: +`interface A { + bar: string +} + +function foo1 (_a: () => number ) { } +foo1(() => (1)) +function foo2 (_a: () => A) { } +foo2(() => ({ bar: '1' })) +foo2(() => ({ bar: '1' })) +function foo3 (_a: () => A | number) { } +foo3(() => (1)) +foo3(() => ({ bar: '1' })) + +function bar1 (): number { + 1 +} +function bar2 (): A { + { bar: '1' } +} +function bar3 (): A { + bar: '1' +} +function bar4 (): A | number { + 1 +} +function bar5(): A | number { + bar: '1' +} +const baz1: () => number = () => (1) +const baz2: () => A = () => ({ bar: '1' }) +const baz3: () => A = () => ({ bar: '1' }) +const baz4: ((() => number) | (() => A)) = () => (1) +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +}); From aca172239c9ba451a0de8ab448ce2059d7f549a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Mon, 20 Aug 2018 10:22:26 +0800 Subject: [PATCH 05/20] add more testcase and fix all test --- src/services/codefixes/returnValueSurmise.ts | 53 ++++++++++++++----- .../fourslash/codeFixSurmiseReturnValue18.ts | 17 ++++++ .../fourslash/codeFixSurmiseReturnValue19.ts | 19 +++++++ .../fourslash/codeFixSurmiseReturnValue20.ts | 23 ++++++++ .../fourslash/codeFixSurmiseReturnValue21.ts | 15 ++++++ .../fourslash/codeFixSurmiseReturnValue22.ts | 17 ++++++ .../fourslash/codeFixSurmiseReturnValue23.ts | 11 ++++ .../codeFixSurmiseReturnValue_all1.ts | 8 ++- .../codeFixSurmiseReturnValue_all2.ts | 6 ++- .../codeFixSurmiseReturnValue_all3.ts | 6 ++- .../codeFixSurmiseReturnValue_all4.ts | 6 ++- 11 files changed, 164 insertions(+), 17 deletions(-) create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue18.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue19.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue20.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue21.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue22.ts create mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue23.ts diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts index 791e9c8ff6f92..0ad39875acc67 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueSurmise.ts @@ -34,8 +34,8 @@ namespace ts.codefix { errorCodes, fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdReplaceBraceWithParen, fixIdWrapTheBlockWithParen], getCodeActions: context => { - const { program, sourceFile, span: { start } } = context; - const info = getInfo(program.getTypeChecker(), sourceFile, start); + const { program, sourceFile, span: { start }, errorCode } = context; + const info = getInfo(program.getTypeChecker(), sourceFile, start, errorCode); if (!info) return undefined; if (info.kind === FixKind.MissingReturnStatement) { @@ -51,7 +51,7 @@ namespace ts.codefix { } }, getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start); + const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start, diag.code); if (!info) return undefined; switch (context.fixId) { @@ -141,30 +141,57 @@ namespace ts.codefix { return checker.isTypeAssignableTo(checker.getTypeAtLocation(isFunctionType ? updateFunctionLikeBody(declaration, createBlock([createReturn(expr)])) : expr), type); } - function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number): Info | undefined { + function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, errorCode: number): Info | undefined { const node = getTokenAtPosition(sourceFile, position); if (!node.parent) return undefined; const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); - if (declaration) { - if (declaration.body && declaration.type && rangeContainsRange(declaration.type, node)) { + switch (errorCode) { + case Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code: + if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return undefined; return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /* isFunctionType */ false); - } - else if (isCallExpression(declaration.parent) && declaration.body) { + case Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code: + if (!declaration || !isCallExpression(declaration.parent) || !declaration.body) return undefined; const pos = declaration.parent.arguments.indexOf(declaration); const type = checker.getContextualTypeForArgumentAtIndex(declaration.parent, pos); if (!type) return undefined; return getFixInfo(checker, declaration, type, /* isFunctionType */ true); - } + case Diagnostics.Type_0_is_not_assignable_to_type_1.code: + if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) return undefined; + const initializer = getVariableLikeInitializer(node.parent); + if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; + return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true); } - else if (isDeclarationName(node) && isVariableDeclaration(node.parent) && node.parent.initializer && node.parent.type) { - const initializer = skipParentheses(node.parent.initializer); - if (!isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; - return getFixInfo(checker, initializer, checker.getTypeFromTypeNode(node.parent.type), /* isFunctionType */ true); + + if (isDeclarationName(node) && (isVariableLike(node.parent) || isJsxAttribute(node.parent))) { + const initializer = getVariableLikeInitializer(node.parent); + if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; + return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true); } return undefined; } + function getVariableLikeInitializer(declaration: VariableLikeDeclaration): Expression | undefined { + switch (declaration.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertyAssignment: + return declaration.initializer; + case SyntaxKind.JsxAttribute: + return declaration.initializer && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined); + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.PropertySignature: + case SyntaxKind.EnumMember: + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocParameterTag: + return undefined; + default: + Debug.fail("unexpected token"); + } + } + function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, expression: Expression) { changes.replaceNode(sourceFile, declaration.body!, createBlock([createReturn(expression)])); } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts new file mode 100644 index 0000000000000..c731ff1486aad --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts @@ -0,0 +1,17 @@ +/// + +//@Filename: file.tsx +//// declare module JSX { +//// interface Element { } +//// interface IntrinsicElements { +//// } +//// interface ElementAttributesProperty { props; } +//// } +//// class Comp { props: { t: () => number } } +//// var x = { 1 }} />; + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts new file mode 100644 index 0000000000000..ae694d561e770 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts @@ -0,0 +1,19 @@ +/// + +//@Filename: file.tsx +//// declare module JSX { +//// interface Element { } +//// interface IntrinsicElements { +//// } +//// interface ElementAttributesProperty { props; } +//// } +//// interface A { +//// bar: string +//// } +//// class Comp { props: { t: () => number } } +//// var x = { bar: '1' }} />; + +verify.codeFixAvailable([ + { description: 'Wrap this block with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts new file mode 100644 index 0000000000000..fb7a6f00e657e --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts @@ -0,0 +1,23 @@ +/// + +//@Filename: file.tsx +//// declare module JSX { +//// interface Element { } +//// interface IntrinsicElements { +//// } +//// interface ElementAttributesProperty { props; } +//// } +//// interface A { +//// bar: string +//// } +//// class Comp { props: { t: () => number } } +//// var x = { +//// { bar: '1' } +//// }} />; + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, + { description: 'Remove unused label' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts new file mode 100644 index 0000000000000..dd82c68326437 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts @@ -0,0 +1,15 @@ +/// + +//// interface A { +//// a: () => number +//// } +//// +//// let b: A = { +//// a: () => { 1 } +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts new file mode 100644 index 0000000000000..daa3ef279781c --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts @@ -0,0 +1,17 @@ +/// + +//// interface A { +//// a: () => number +//// } +//// +//// function Foo (): A { +//// return { +//// a: () => { 1 } +//// } +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts new file mode 100644 index 0000000000000..a783ea19348d6 --- /dev/null +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts @@ -0,0 +1,11 @@ +/// + +//// class Foo { +//// bar: () => number = () => { 1 } +//// } + +verify.codeFixAvailable([ + { description: 'Add a return statement' }, + { description: 'Remove block body braces' }, + { description: 'Replace braces with parentheses' }, +]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index 404015144937f..f964064439728 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixAddReturnStatement", @@ -111,5 +113,9 @@ const baz4: ((() => number) | (() => A)) = () => { } const baz5: ((() => number) | (() => A)) = () => { return { bar: '1' }; -}`, +} + +const test: { a: A } = { a: () => { + return { bar: '1' }; +} }`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts index 5061018f1feb0..b6edba3815fff 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixRemoveBlockBodyBrace", @@ -91,5 +93,7 @@ const baz1: () => number = () => 1 const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => 1 -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: A } = { a: () => ({ bar: '1' }) }`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts index 31d71cda5439c..5fad951c250cb 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixReplaceBraceWithParen", @@ -91,5 +93,7 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: A } = { a: () => ({ bar: '1' }) }`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts index 760e422580338..30c3323c2a201 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixWrapTheBlockWithParen", @@ -91,5 +93,7 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: A } = { a: () => ({ bar: '1' }) }`, }); From cbe59bb06344958113b3e2a37f33edca95f41653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Tue, 30 Apr 2019 15:17:24 +0800 Subject: [PATCH 06/20] fix changed diagnosis --- src/services/codefixes/returnValueSurmise.ts | 8 -------- tests/cases/fourslash/codeFixSurmiseReturnValue18.ts | 1 + tests/cases/fourslash/codeFixSurmiseReturnValue19.ts | 1 + tests/cases/fourslash/codeFixSurmiseReturnValue20.ts | 1 + .../cases/fourslash/codeFixSurmiseReturnValue_all1.ts | 10 ++-------- .../cases/fourslash/codeFixSurmiseReturnValue_all2.ts | 6 +----- .../cases/fourslash/codeFixSurmiseReturnValue_all3.ts | 6 +----- .../cases/fourslash/codeFixSurmiseReturnValue_all4.ts | 6 +----- 8 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueSurmise.ts index 0ad39875acc67..80864db326498 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueSurmise.ts @@ -162,12 +162,6 @@ namespace ts.codefix { if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true); } - - if (isDeclarationName(node) && (isVariableLike(node.parent) || isJsxAttribute(node.parent))) { - const initializer = getVariableLikeInitializer(node.parent); - if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; - return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true); - } return undefined; } @@ -187,8 +181,6 @@ namespace ts.codefix { case SyntaxKind.JSDocPropertyTag: case SyntaxKind.JSDocParameterTag: return undefined; - default: - Debug.fail("unexpected token"); } } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts index c731ff1486aad..4f5180f43b267 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts @@ -14,4 +14,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, { description: 'Replace braces with parentheses' }, + { description: `Infer type of 'props' from usage` } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts index ae694d561e770..88e1556ce9838 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts @@ -15,5 +15,6 @@ verify.codeFixAvailable([ { description: 'Wrap this block with parentheses' }, + { description: `Infer type of 'props' from usage` }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts index fb7a6f00e657e..fa0d4245e0523 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts @@ -19,5 +19,6 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, { description: 'Replace braces with parentheses' }, + { description: `Infer type of 'props' from usage` }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index f964064439728..34efa0a3b2050 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -54,8 +54,6 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } -//// -//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixAddReturnStatement", @@ -113,9 +111,5 @@ const baz4: ((() => number) | (() => A)) = () => { } const baz5: ((() => number) | (() => A)) = () => { return { bar: '1' }; -} - -const test: { a: A } = { a: () => { - return { bar: '1' }; -} }`, -}); +}`, +}); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts index b6edba3815fff..5061018f1feb0 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -54,8 +54,6 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } -//// -//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixRemoveBlockBodyBrace", @@ -93,7 +91,5 @@ const baz1: () => number = () => 1 const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => 1 -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) - -const test: { a: A } = { a: () => ({ bar: '1' }) }`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts index 5fad951c250cb..31d71cda5439c 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -54,8 +54,6 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } -//// -//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixReplaceBraceWithParen", @@ -93,7 +91,5 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) - -const test: { a: A } = { a: () => ({ bar: '1' }) }`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts index 30c3323c2a201..760e422580338 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts @@ -54,8 +54,6 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } -//// -//// const test: { a: A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixWrapTheBlockWithParen", @@ -93,7 +91,5 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) - -const test: { a: A } = { a: () => ({ bar: '1' }) }`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, }); From 98d7ebaca496d2ff6d5aabded69b88c49ec6a327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Wed, 8 May 2019 17:08:16 +0800 Subject: [PATCH 07/20] fix broken test case --- tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts | 3 ++- tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts | 3 ++- tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts | 1 + tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts | 1 + tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts | 1 + tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts | 1 + tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts | 1 + tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts | 1 + 8 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts index 42e0bc5be780f..24a4f7cbca4bc 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts @@ -5,9 +5,10 @@ ////} verify.codeFix({ + index: 3, description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { await Promise.resolve('foo'); -}`, +}` }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts index bc7b17f8db5b4..c1e80654cf0c0 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts @@ -6,9 +6,10 @@ // should not change type if it's incorrectly set verify.codeFix({ + index: 3, description: "Add async modifier to containing function", newFileContent: `const f: string = async () => { await Promise.resolve('foo'); -}`, +}` }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts index ee694a80e9f26..4e780d4b57dbc 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts @@ -5,6 +5,7 @@ ////} verify.codeFix({ + index: 1, description: "Add async modifier to containing function", newFileContent: `const f: () => Promise> = async function() { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts index 06f54d29eeb68..201b7c2f37df8 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts @@ -5,6 +5,7 @@ ////} verify.codeFix({ + index: 3, description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts index c798af5f5abd6..7b9ca8c7239a7 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts @@ -5,6 +5,7 @@ ////} verify.codeFix({ + index: 1, description: "Add async modifier to containing function", newFileContent: `const f = async function(): Promise { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts index a2c6f7dcb1ad9..a6ca0b7d4fb1d 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts @@ -5,6 +5,7 @@ ////} verify.codeFix({ + index: 3, description: "Add async modifier to containing function", newFileContent: `const f = async (): Promise => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts index 7c43add3edd21..726927b77b793 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts @@ -5,6 +5,7 @@ ////} verify.codeFix({ + index: 1, description: "Add async modifier to containing function", newFileContent: `async function f(): Promise { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts index f93603e69c457..652a669832e32 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts @@ -7,6 +7,7 @@ ////} verify.codeFix({ + index: 1, description: "Add async modifier to containing function", newFileContent: `class Foo { From 537e806b03fbe7d4337c8221dcae3a5e10e2391c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Wed, 8 May 2019 17:34:58 +0800 Subject: [PATCH 08/20] add more case --- tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts | 8 +++++++- tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts | 6 +++++- tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts | 6 +++++- tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts | 6 +++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index 34efa0a3b2050..8f5b960393f98 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: () => A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixAddReturnStatement", @@ -111,5 +113,9 @@ const baz4: ((() => number) | (() => A)) = () => { } const baz5: ((() => number) | (() => A)) = () => { return { bar: '1' }; -}`, +} + +const test: { a: () => A } = { a: () => { + return { bar: '1' }; +} }`, }); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts index 5061018f1feb0..2078b456e0253 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: () => A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixRemoveBlockBodyBrace", @@ -91,5 +93,7 @@ const baz1: () => number = () => 1 const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => 1 -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: () => A } = { a: () => ({ bar: '1' }) }`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts index 31d71cda5439c..4980cdd9c09be 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: () => A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixReplaceBraceWithParen", @@ -91,5 +93,7 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: () => A } = { a: () => ({ bar: '1' }) }`, }); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts index 760e422580338..1f5a1b08f2010 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts @@ -54,6 +54,8 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// +//// const test: { a: () => A } = { a: () => { bar: '1' } } verify.codeFixAll({ fixId: "fixWrapTheBlockWithParen", @@ -91,5 +93,7 @@ const baz1: () => number = () => (1) const baz2: () => A = () => ({ bar: '1' }) const baz3: () => A = () => ({ bar: '1' }) const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' })`, +const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) + +const test: { a: () => A } = { a: () => ({ bar: '1' }) }`, }); From 6fecf32dbc18fa1d63dbb47c0b519a4fa8f39cdb Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 9 Jan 2020 19:04:18 +0800 Subject: [PATCH 09/20] rename quickfix --- .../{returnValueSurmise.ts => returnValueCorrect.ts} | 10 +++++----- src/services/tsconfig.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/services/codefixes/{returnValueSurmise.ts => returnValueCorrect.ts} (96%) diff --git a/src/services/codefixes/returnValueSurmise.ts b/src/services/codefixes/returnValueCorrect.ts similarity index 96% rename from src/services/codefixes/returnValueSurmise.ts rename to src/services/codefixes/returnValueCorrect.ts index 80864db326498..bff6a4c58dca3 100644 --- a/src/services/codefixes/returnValueSurmise.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -1,6 +1,6 @@ /* @internal */ namespace ts.codefix { - const fixId = "returnValueSurmise"; + const fixId = "returnValueCorrect"; const fixIdAddReturnStatement = "fixAddReturnStatement"; const fixIdRemoveBlockBodyBrace = "fixRemoveBlockBodyBrace"; const fixIdReplaceBraceWithParen = "fixReplaceBraceWithParen"; @@ -198,21 +198,21 @@ namespace ts.codefix { function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Surmise_all_return_value); + return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Correct_all_return_expressions); } function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ false)); - return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Surmise_all_return_value); + return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Correct_all_return_expressions); } function getActionForfixReplaceBraceWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ true)); - return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Surmise_all_return_value); + return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Correct_all_return_expressions); } function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Surmise_all_return_value); + return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Correct_all_return_expressions); } } diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 759cd59fa28b8..c6bc06b1a1ee8 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -62,7 +62,7 @@ "codefixes/fixClassIncorrectlyImplementsInterface.ts", "codefixes/importFixes.ts", "codefixes/fixSpelling.ts", - "codefixes/returnValueSurmise.ts", + "codefixes/returnValueCorrect.ts", "codefixes/fixAddMissingMember.ts", "codefixes/fixAddMissingNewOperator.ts", "codefixes/fixCannotFindModule.ts", From 4c0af7279f3127265da19e4e1fe1138d3045c87c Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 9 Jan 2020 19:10:50 +0800 Subject: [PATCH 10/20] fix conflict --- src/compiler/checker.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 791563181e20b..8e8157fc025ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -536,9 +536,7 @@ namespace ts { }, getApparentType, getUnionType, - isTypeAssignableTo: (source, target) => { - return isTypeAssignableTo(source, target); - }, + isTypeAssignableTo, createAnonymousType, createSignature, createSymbol, @@ -564,7 +562,6 @@ namespace ts { isArrayLikeType, isTypeInvalidDueToUnionDiscriminant, getAllPossiblePropertiesOfTypes, - isTypeAssignableTo, getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type), getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), getSuggestionForNonexistentExport: (node, target) => getSuggestionForNonexistentExport(node, target), From 98377f380f2207879e25105b8a92c81c02ecfc4c Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 9 Jan 2020 23:44:50 +0800 Subject: [PATCH 11/20] fix fix desc --- tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index 8f5b960393f98..c0055060857bd 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixAddReturnStatement", - fixAllDescription: "Surmise all return value", + fixAllDescription: "Correct all return expressions", newFileContent: `interface A { bar: string diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts index 2078b456e0253..af236faf31b33 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixRemoveBlockBodyBrace", - fixAllDescription: "Surmise all return value", + fixAllDescription: "Correct all return expressions", newFileContent: `interface A { bar: string diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts index 4980cdd9c09be..a2d536ec61771 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixReplaceBraceWithParen", - fixAllDescription: "Surmise all return value", + fixAllDescription: "Correct all return expressions", newFileContent: `interface A { bar: string diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts index 1f5a1b08f2010..23909d3672e73 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixWrapTheBlockWithParen", - fixAllDescription: "Surmise all return value", + fixAllDescription: "Correct all return expressions", newFileContent: `interface A { bar: string From 49d21bf0c6c6fd8bd77f6d08e71a32910a8b3bb6 Mon Sep 17 00:00:00 2001 From: kingwl Date: Fri, 10 Jan 2020 00:24:33 +0800 Subject: [PATCH 12/20] fix semi --- src/compiler/types.ts | 1 - .../codeFixSurmiseReturnValue_all1.ts | 32 +++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f346b8cb2b413..98f2531b6c6d1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3546,7 +3546,6 @@ namespace ts { * e.g. it specifies `kind: "a"` and obj has `kind: "b"`. */ /* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean; - /* @internal */ isTypeAssignableTo(type1: Type, type2: Type): boolean; /** * For a union, will include a property if it's defined in *any* of the member types. * So for `{ a } | { b }`, this will include both `a` and `b`. diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index c0055060857bd..7e8cfb125f0a7 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -67,55 +67,55 @@ verify.codeFixAll({ function foo1 (_a: () => number ) { } foo1(() => { - return 1; + return 1 }) function foo2 (_a: () => A) { } foo2(() => { - return { bar: '1' }; + return { bar: '1' } }) foo2(() => { - return { bar: '1' }; + return { bar: '1' } }) function foo3 (_a: () => A | number) { } foo3(() => { - return 1; + return 1 }) foo3(() => { - return { bar: '1' }; + return { bar: '1' } }) function bar1 (): number { - return 1; + return 1 } function bar2 (): A { - return { bar: '1' }; + return { bar: '1' } } function bar3 (): A { - return { bar: '1' }; + return { bar: '1' } } function bar4 (): A | number { - return 1; + return 1 } function bar5(): A | number { - return { bar: '1' }; + return { bar: '1' } } const baz1: () => number = () => { - return 1; + return 1 } const baz2: () => A = () => { - return { bar: '1' }; + return { bar: '1' } } const baz3: () => A = () => { - return { bar: '1' }; + return { bar: '1' } } const baz4: ((() => number) | (() => A)) = () => { - return 1; + return 1 } const baz5: ((() => number) | (() => A)) = () => { - return { bar: '1' }; + return { bar: '1' } } const test: { a: () => A } = { a: () => { - return { bar: '1' }; + return { bar: '1' } } }`, }); \ No newline at end of file From 944ddf46e9fb18b078068603da00e64c84273b78 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 18 Mar 2020 09:16:48 +0800 Subject: [PATCH 13/20] Avoid replace brace with paren --- src/compiler/diagnosticMessages.json | 8 +- src/services/codefixes/returnValueCorrect.ts | 19 +--- .../fourslash/codeFixSurmiseReturnValue10.ts | 3 +- .../fourslash/codeFixSurmiseReturnValue12.ts | 1 - .../fourslash/codeFixSurmiseReturnValue13.ts | 1 - .../fourslash/codeFixSurmiseReturnValue18.ts | 1 - .../fourslash/codeFixSurmiseReturnValue20.ts | 1 - .../fourslash/codeFixSurmiseReturnValue21.ts | 1 - .../fourslash/codeFixSurmiseReturnValue22.ts | 1 - .../fourslash/codeFixSurmiseReturnValue23.ts | 3 +- .../fourslash/codeFixSurmiseReturnValue7.ts | 3 +- .../fourslash/codeFixSurmiseReturnValue8.ts | 3 +- .../fourslash/codeFixSurmiseReturnValue9.ts | 3 +- .../codeFixSurmiseReturnValue_all3.ts | 99 ------------------- 14 files changed, 10 insertions(+), 137 deletions(-) delete mode 100644 tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c65d4b9ac6f3a..cf8fc21f512a1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5505,17 +5505,13 @@ "category": "Message", "code": 95103 }, - "Replace braces with parentheses": { - "category": "Message", - "code": 95104 - }, "Wrap this block with parentheses": { "category": "Message", - "code": 95105 + "code": 95104 }, "Correct all return expressions": { "category": "Message", - "code": 95106 + "code": 95105 }, "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index bff6a4c58dca3..b6de942ce62bf 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -3,7 +3,6 @@ namespace ts.codefix { const fixId = "returnValueCorrect"; const fixIdAddReturnStatement = "fixAddReturnStatement"; const fixIdRemoveBlockBodyBrace = "fixRemoveBlockBodyBrace"; - const fixIdReplaceBraceWithParen = "fixReplaceBraceWithParen"; const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen"; const errorCodes = [ Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code, @@ -32,19 +31,16 @@ namespace ts.codefix { registerCodeFix({ errorCodes, - fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdReplaceBraceWithParen, fixIdWrapTheBlockWithParen], + fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdWrapTheBlockWithParen], getCodeActions: context => { const { program, sourceFile, span: { start }, errorCode } = context; const info = getInfo(program.getTypeChecker(), sourceFile, start, errorCode); if (!info) return undefined; if (info.kind === FixKind.MissingReturnStatement) { - return concatenate( + return append( [getActionForfixAddReturnStatement(context, info.declaration, info.expression)], - isArrowFunction(info.declaration) ? [ - getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression), - getActionForfixReplaceBraceWithParen(context, info.declaration, info.expression) - ] : undefined); + isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression): undefined); } else { return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)]; @@ -62,10 +58,6 @@ namespace ts.codefix { if (!isArrowFunction(info.declaration)) return undefined; removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, /* withParen */ false); break; - case fixIdReplaceBraceWithParen: - if (!isArrowFunction(info.declaration)) return undefined; - removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, /* withParen */ true); - break; case fixIdWrapTheBlockWithParen: if (!isArrowFunction(info.declaration)) return undefined; wrapBlockWithParen(changes, diag.file, info.declaration, info.expression); @@ -206,11 +198,6 @@ namespace ts.codefix { return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Correct_all_return_expressions); } - function getActionForfixReplaceBraceWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ true)); - return createCodeFixAction(fixId, changes, Diagnostics.Replace_braces_with_parentheses, fixIdReplaceBraceWithParen, Diagnostics.Correct_all_return_expressions); - } - function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Correct_all_return_expressions); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts index c8a94d90a7d6d..cdbf416984d58 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts @@ -4,6 +4,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, + { description: 'Remove block body braces' } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts index 8672eb7882fd0..d242e4f4cf87e 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts @@ -11,6 +11,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts index 37360499d9e5e..a1e2cc553ccac 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts @@ -10,7 +10,6 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts index 4f5180f43b267..ffa038a48fc5c 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts @@ -13,6 +13,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, { description: `Infer type of 'props' from usage` } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts index fa0d4245e0523..f552edaee6713 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts @@ -18,7 +18,6 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, { description: `Infer type of 'props' from usage` }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts index dd82c68326437..1a248f77909f2 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts @@ -11,5 +11,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts index daa3ef279781c..372513592afb8 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts @@ -13,5 +13,4 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts index a783ea19348d6..14fde02533799 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts @@ -6,6 +6,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, + { description: 'Remove block body braces' } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts index 5a40e0a7f66dd..bd0bfd3b343b3 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts @@ -5,6 +5,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, + { description: 'Remove block body braces' } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts index 8ebc2500cabcc..cde3ab2e42ff6 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts @@ -5,6 +5,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, + { description: 'Remove block body braces' } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts index 8abf79d631f7b..104fd785f00a1 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts @@ -4,6 +4,5 @@ verify.codeFixAvailable([ { description: 'Add a return statement' }, - { description: 'Remove block body braces' }, - { description: 'Replace braces with parentheses' }, + { description: 'Remove block body braces' } ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts deleted file mode 100644 index a2d536ec61771..0000000000000 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts +++ /dev/null @@ -1,99 +0,0 @@ -/// - -//// interface A { -//// bar: string -//// } -//// -//// function foo1 (_a: () => number ) { } -//// foo1(() => { -//// 1 -//// }) -//// function foo2 (_a: () => A) { } -//// foo2(() => { -//// { bar: '1' } -//// }) -//// foo2(() => { -//// bar: '1' -//// }) -//// function foo3 (_a: () => A | number) { } -//// foo3(() => { -//// 1 -//// }) -//// foo3(() => { -//// bar: '1' -//// }) -//// -//// function bar1 (): number { -//// 1 -//// } -//// function bar2 (): A { -//// { bar: '1' } -//// } -//// function bar3 (): A { -//// bar: '1' -//// } -//// function bar4 (): A | number { -//// 1 -//// } -//// function bar5(): A | number { -//// bar: '1' -//// } -// -//// const baz1: () => number = () => { -//// 1 -//// } -//// const baz2: () => A = () => { -//// { bar: '1' } -//// } -//// const baz3: () => A = () => { -//// bar: '1' -//// } -//// const baz4: ((() => number) | (() => A)) = () => { -//// 1 -//// } -//// const baz5: ((() => number) | (() => A)) = () => { -//// bar: '1' -//// } -//// -//// const test: { a: () => A } = { a: () => { bar: '1' } } - -verify.codeFixAll({ - fixId: "fixReplaceBraceWithParen", - fixAllDescription: "Correct all return expressions", - newFileContent: -`interface A { - bar: string -} - -function foo1 (_a: () => number ) { } -foo1(() => (1)) -function foo2 (_a: () => A) { } -foo2(() => ({ bar: '1' })) -foo2(() => ({ bar: '1' })) -function foo3 (_a: () => A | number) { } -foo3(() => (1)) -foo3(() => ({ bar: '1' })) - -function bar1 (): number { - 1 -} -function bar2 (): A { - { bar: '1' } -} -function bar3 (): A { - bar: '1' -} -function bar4 (): A | number { - 1 -} -function bar5(): A | number { - bar: '1' -} -const baz1: () => number = () => (1) -const baz2: () => A = () => ({ bar: '1' }) -const baz3: () => A = () => ({ bar: '1' }) -const baz4: ((() => number) | (() => A)) = () => (1) -const baz5: ((() => number) | (() => A)) = () => ({ bar: '1' }) - -const test: { a: () => A } = { a: () => ({ bar: '1' }) }`, -}); From 6c88a01a286b1c3d23b8040586c372774d9c6f0b Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 18 Mar 2020 09:26:24 +0800 Subject: [PATCH 14/20] Split fix all action --- src/compiler/diagnosticMessages.json | 12 ++++++++++-- src/services/codefixes/returnValueCorrect.ts | 6 +++--- tests/cases/fourslash/codeFixSurmiseReturnValue14.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue15.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue16.ts | 2 +- tests/cases/fourslash/codeFixSurmiseReturnValue19.ts | 2 +- .../fourslash/codeFixSurmiseReturnValue_all1.ts | 2 +- .../fourslash/codeFixSurmiseReturnValue_all2.ts | 2 +- ...lue_all4.ts => codeFixSurmiseReturnValue_all3.ts} | 2 +- 9 files changed, 20 insertions(+), 12 deletions(-) rename tests/cases/fourslash/{codeFixSurmiseReturnValue_all4.ts => codeFixSurmiseReturnValue_all3.ts} (96%) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index cf8fc21f512a1..3c38c5f07e3cb 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5505,14 +5505,22 @@ "category": "Message", "code": 95103 }, - "Wrap this block with parentheses": { + "Wrap this object literal with parentheses": { "category": "Message", "code": 95104 }, - "Correct all return expressions": { + "Add all missing return statement": { "category": "Message", "code": 95105 }, + "Remove all incorrect body block braces": { + "category": "Message", + "code": 95106 + }, + "Wrap all object literal with parentheses": { + "category": "Message", + "code": 95107 + }, "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { "category": "Error", diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index b6de942ce62bf..a0623b64700cb 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -190,16 +190,16 @@ namespace ts.codefix { function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Correct_all_return_expressions); + return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement); } function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ false)); - return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Correct_all_return_expressions); + return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Remove_all_incorrect_body_block_braces); } function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_block_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Correct_all_return_expressions); + return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_object_literal_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses); } } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts index 59091741c13d8..8951f82993d0b 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts @@ -8,6 +8,6 @@ //// } verify.codeFixAvailable([ - { description: 'Wrap this block with parentheses' }, + { description: 'Wrap this object literal with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts index 8e2970fea2c0e..b6ba1824293b3 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts @@ -7,6 +7,6 @@ //// Foo(() => { bar: '1' }) verify.codeFixAvailable([ - { description: 'Wrap this block with parentheses' }, + { description: 'Wrap this object literal with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts index 5292a10f776e7..1a8e685ab6f30 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts @@ -8,6 +8,6 @@ //// Foo(() => { bar: '1' }) verify.codeFixAvailable([ - { description: 'Wrap this block with parentheses' }, + { description: 'Wrap this object literal with parentheses' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts index 88e1556ce9838..00ef70a3a1840 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts @@ -14,7 +14,7 @@ //// var x = { bar: '1' }} />; verify.codeFixAvailable([ - { description: 'Wrap this block with parentheses' }, + { description: 'Wrap this object literal with parentheses' }, { description: `Infer type of 'props' from usage` }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index 7e8cfb125f0a7..bda9f16663f3f 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixAddReturnStatement", - fixAllDescription: "Correct all return expressions", + fixAllDescription: "Add all missing return statement", newFileContent: `interface A { bar: string diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts index af236faf31b33..e3b0d1c0b1d39 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixRemoveBlockBodyBrace", - fixAllDescription: "Correct all return expressions", + fixAllDescription: "Remove all incorrect body block braces", newFileContent: `interface A { bar: string diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts similarity index 96% rename from tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts rename to tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts index 23909d3672e73..0d4806b19c18c 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all4.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts @@ -59,7 +59,7 @@ verify.codeFixAll({ fixId: "fixWrapTheBlockWithParen", - fixAllDescription: "Correct all return expressions", + fixAllDescription: "Wrap all object literal with parentheses", newFileContent: `interface A { bar: string From 94f845af510946ba473348792b94912292db04e4 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 18 Mar 2020 09:51:44 +0800 Subject: [PATCH 15/20] Add return work in same line --- src/services/codefixes/returnValueCorrect.ts | 26 ++++++++++++------- .../codeFixSurmiseReturnValue_all1.ts | 6 ++--- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index a0623b64700cb..ad440e561430c 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -19,12 +19,14 @@ namespace ts.codefix { kind: FixKind.MissingReturnStatement; declaration: FunctionLikeDeclaration; expression: Expression; + statement: Statement; } interface MissingParenInfo { kind: FixKind.MissingParentheses; declaration: ArrowFunction; expression: Expression; + statement: Statement; } type Info = MissingReturnInfo | MissingParenInfo; @@ -39,7 +41,7 @@ namespace ts.codefix { if (info.kind === FixKind.MissingReturnStatement) { return append( - [getActionForfixAddReturnStatement(context, info.declaration, info.expression)], + [getActionForfixAddReturnStatement(context, info.expression, info.statement)], isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression): undefined); } else { @@ -52,7 +54,7 @@ namespace ts.codefix { switch (context.fixId) { case fixIdAddReturnStatement: - addReturnStatement(changes, diag.file, info.declaration, info.expression); + addReturnStatement(changes, diag.file, info.expression, info.statement); break; case fixIdRemoveBlockBodyBrace: if (!isArrowFunction(info.declaration)) return undefined; @@ -95,7 +97,8 @@ namespace ts.codefix { return { declaration, kind: FixKind.MissingReturnStatement, - expression: firstStatement.expression + expression: firstStatement.expression, + statement: firstStatement }; } else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { @@ -104,11 +107,13 @@ namespace ts.codefix { return isArrowFunction(declaration) ? { declaration, kind: FixKind.MissingParentheses, - expression: node + expression: node, + statement: firstStatement } : { declaration, kind: FixKind.MissingReturnStatement, - expression: node + expression: node, + statement: firstStatement }; } } @@ -120,7 +125,8 @@ namespace ts.codefix { return { declaration, kind: FixKind.MissingReturnStatement, - expression: node + expression: node, + statement: firstStatement }; } } @@ -176,8 +182,8 @@ namespace ts.codefix { } } - function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: FunctionLikeDeclaration, expression: Expression) { - changes.replaceNode(sourceFile, declaration.body!, createBlock([createReturn(expression)])); + function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) { + changes.replaceNode(sourceFile, statement, createReturn(expression)); } function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, withParen: boolean) { @@ -188,8 +194,8 @@ namespace ts.codefix { changes.replaceNode(sourceFile, declaration.body, createParen(expression)); } - function getActionForfixAddReturnStatement(context: CodeFixContext, declaration: FunctionLikeDeclaration, expression: Expression) { - const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, declaration, expression)); + function getActionForfixAddReturnStatement(context: CodeFixContext, expression: Expression, statement: Statement) { + const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, expression, statement)); return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement); } diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts index bda9f16663f3f..e14f31e5e8b9c 100644 --- a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts +++ b/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts @@ -54,6 +54,7 @@ //// const baz5: ((() => number) | (() => A)) = () => { //// bar: '1' //// } +//// const baz6: () => number = () => { 1 } //// //// const test: { a: () => A } = { a: () => { bar: '1' } } @@ -114,8 +115,7 @@ const baz4: ((() => number) | (() => A)) = () => { const baz5: ((() => number) | (() => A)) = () => { return { bar: '1' } } +const baz6: () => number = () => { return 1 } -const test: { a: () => A } = { a: () => { - return { bar: '1' } -} }`, +const test: { a: () => A } = { a: () => { return { bar: '1' } } }`, }); \ No newline at end of file From 7fe9a82928d77d548894b46b9a88e579d6595097 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 18 Mar 2020 10:31:05 +0800 Subject: [PATCH 16/20] fix test cases --- tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts index 24a4f7cbca4bc..3518b017050ee 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - index: 3, + index: 2, description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts index c1e80654cf0c0..1cfce8eda2e39 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts @@ -6,7 +6,7 @@ // should not change type if it's incorrectly set verify.codeFix({ - index: 3, + index: 2, description: "Add async modifier to containing function", newFileContent: `const f: string = async () => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts index 201b7c2f37df8..57fb74a4fe091 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - index: 3, + index: 2, description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts index a6ca0b7d4fb1d..47f474ecb0c61 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - index: 3, + index: 2, description: "Add async modifier to containing function", newFileContent: `const f = async (): Promise => { From af9552edb26d708794a2c0680b2384d0f8e0929c Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 26 Mar 2020 21:53:47 +0800 Subject: [PATCH 17/20] rename baseline --- ...odeFixSurmiseReturnValue1.ts => codeFixCorrectReturnValue1.ts} | 0 ...eFixSurmiseReturnValue10.ts => codeFixCorrectReturnValue10.ts} | 0 ...eFixSurmiseReturnValue11.ts => codeFixCorrectReturnValue11.ts} | 0 ...eFixSurmiseReturnValue12.ts => codeFixCorrectReturnValue12.ts} | 0 ...eFixSurmiseReturnValue13.ts => codeFixCorrectReturnValue13.ts} | 0 ...eFixSurmiseReturnValue14.ts => codeFixCorrectReturnValue14.ts} | 0 ...eFixSurmiseReturnValue15.ts => codeFixCorrectReturnValue15.ts} | 0 ...eFixSurmiseReturnValue16.ts => codeFixCorrectReturnValue16.ts} | 0 ...eFixSurmiseReturnValue17.ts => codeFixCorrectReturnValue17.ts} | 0 ...eFixSurmiseReturnValue18.ts => codeFixCorrectReturnValue18.ts} | 0 ...eFixSurmiseReturnValue19.ts => codeFixCorrectReturnValue19.ts} | 0 ...odeFixSurmiseReturnValue2.ts => codeFixCorrectReturnValue2.ts} | 0 ...eFixSurmiseReturnValue20.ts => codeFixCorrectReturnValue20.ts} | 0 ...eFixSurmiseReturnValue21.ts => codeFixCorrectReturnValue21.ts} | 0 ...eFixSurmiseReturnValue22.ts => codeFixCorrectReturnValue22.ts} | 0 ...eFixSurmiseReturnValue23.ts => codeFixCorrectReturnValue23.ts} | 0 ...odeFixSurmiseReturnValue3.ts => codeFixCorrectReturnValue3.ts} | 0 ...odeFixSurmiseReturnValue4.ts => codeFixCorrectReturnValue4.ts} | 0 ...odeFixSurmiseReturnValue5.ts => codeFixCorrectReturnValue5.ts} | 0 ...odeFixSurmiseReturnValue6.ts => codeFixCorrectReturnValue6.ts} | 0 ...odeFixSurmiseReturnValue7.ts => codeFixCorrectReturnValue7.ts} | 0 ...odeFixSurmiseReturnValue8.ts => codeFixCorrectReturnValue8.ts} | 0 ...odeFixSurmiseReturnValue9.ts => codeFixCorrectReturnValue9.ts} | 0 ...rmiseReturnValue_all1.ts => codeFixCorrectReturnValue_all1.ts} | 0 ...rmiseReturnValue_all2.ts => codeFixCorrectReturnValue_all2.ts} | 0 ...rmiseReturnValue_all3.ts => codeFixCorrectReturnValue_all3.ts} | 0 26 files changed, 0 insertions(+), 0 deletions(-) rename tests/cases/fourslash/{codeFixSurmiseReturnValue1.ts => codeFixCorrectReturnValue1.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue10.ts => codeFixCorrectReturnValue10.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue11.ts => codeFixCorrectReturnValue11.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue12.ts => codeFixCorrectReturnValue12.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue13.ts => codeFixCorrectReturnValue13.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue14.ts => codeFixCorrectReturnValue14.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue15.ts => codeFixCorrectReturnValue15.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue16.ts => codeFixCorrectReturnValue16.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue17.ts => codeFixCorrectReturnValue17.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue18.ts => codeFixCorrectReturnValue18.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue19.ts => codeFixCorrectReturnValue19.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue2.ts => codeFixCorrectReturnValue2.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue20.ts => codeFixCorrectReturnValue20.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue21.ts => codeFixCorrectReturnValue21.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue22.ts => codeFixCorrectReturnValue22.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue23.ts => codeFixCorrectReturnValue23.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue3.ts => codeFixCorrectReturnValue3.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue4.ts => codeFixCorrectReturnValue4.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue5.ts => codeFixCorrectReturnValue5.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue6.ts => codeFixCorrectReturnValue6.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue7.ts => codeFixCorrectReturnValue7.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue8.ts => codeFixCorrectReturnValue8.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue9.ts => codeFixCorrectReturnValue9.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue_all1.ts => codeFixCorrectReturnValue_all1.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue_all2.ts => codeFixCorrectReturnValue_all2.ts} (100%) rename tests/cases/fourslash/{codeFixSurmiseReturnValue_all3.ts => codeFixCorrectReturnValue_all3.ts} (100%) diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue1.ts b/tests/cases/fourslash/codeFixCorrectReturnValue1.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue1.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue1.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue10.ts b/tests/cases/fourslash/codeFixCorrectReturnValue10.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue10.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue10.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue11.ts b/tests/cases/fourslash/codeFixCorrectReturnValue11.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue11.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue11.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue12.ts b/tests/cases/fourslash/codeFixCorrectReturnValue12.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue12.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue12.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue13.ts b/tests/cases/fourslash/codeFixCorrectReturnValue13.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue13.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue13.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue14.ts b/tests/cases/fourslash/codeFixCorrectReturnValue14.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue14.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue14.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue15.ts b/tests/cases/fourslash/codeFixCorrectReturnValue15.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue15.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue15.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue16.ts b/tests/cases/fourslash/codeFixCorrectReturnValue16.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue16.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue16.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue17.ts b/tests/cases/fourslash/codeFixCorrectReturnValue17.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue17.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue17.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue18.ts b/tests/cases/fourslash/codeFixCorrectReturnValue18.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue18.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue18.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue19.ts b/tests/cases/fourslash/codeFixCorrectReturnValue19.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue19.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue19.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue2.ts b/tests/cases/fourslash/codeFixCorrectReturnValue2.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue2.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue2.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue20.ts b/tests/cases/fourslash/codeFixCorrectReturnValue20.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue20.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue20.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue21.ts b/tests/cases/fourslash/codeFixCorrectReturnValue21.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue21.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue21.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue22.ts b/tests/cases/fourslash/codeFixCorrectReturnValue22.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue22.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue22.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue23.ts b/tests/cases/fourslash/codeFixCorrectReturnValue23.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue23.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue23.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue3.ts b/tests/cases/fourslash/codeFixCorrectReturnValue3.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue3.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue3.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue4.ts b/tests/cases/fourslash/codeFixCorrectReturnValue4.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue4.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue4.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue5.ts b/tests/cases/fourslash/codeFixCorrectReturnValue5.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue5.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue5.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue6.ts b/tests/cases/fourslash/codeFixCorrectReturnValue6.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue6.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue6.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue7.ts b/tests/cases/fourslash/codeFixCorrectReturnValue7.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue7.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue7.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue8.ts b/tests/cases/fourslash/codeFixCorrectReturnValue8.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue8.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue8.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue9.ts b/tests/cases/fourslash/codeFixCorrectReturnValue9.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue9.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue9.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts b/tests/cases/fourslash/codeFixCorrectReturnValue_all1.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue_all1.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue_all1.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts b/tests/cases/fourslash/codeFixCorrectReturnValue_all2.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue_all2.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue_all2.ts diff --git a/tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts b/tests/cases/fourslash/codeFixCorrectReturnValue_all3.ts similarity index 100% rename from tests/cases/fourslash/codeFixSurmiseReturnValue_all3.ts rename to tests/cases/fourslash/codeFixCorrectReturnValue_all3.ts From 601fc5ea615b3f51c7a1632fe10b253c2104ed50 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 26 Mar 2020 22:26:47 +0800 Subject: [PATCH 18/20] refactor and handle comment --- src/compiler/diagnosticMessages.json | 2 +- src/compiler/factoryPublic.ts | 19 ++++++ src/services/codefixes/returnValueCorrect.ts | 68 ++++++++----------- .../convertParamsToDestructuredObject.ts | 21 ------ src/services/utilities.ts | 21 ++++++ .../fourslash/codeFixCorrectReturnValue14.ts | 2 +- .../fourslash/codeFixCorrectReturnValue15.ts | 2 +- .../fourslash/codeFixCorrectReturnValue16.ts | 2 +- .../fourslash/codeFixCorrectReturnValue19.ts | 2 +- .../fourslash/codeFixCorrectReturnValue24.ts | 12 ++++ .../fourslash/codeFixCorrectReturnValue25.ts | 12 ++++ 11 files changed, 99 insertions(+), 64 deletions(-) create mode 100644 tests/cases/fourslash/codeFixCorrectReturnValue24.ts create mode 100644 tests/cases/fourslash/codeFixCorrectReturnValue25.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index dc36b872bfb0e..8438eb7ec9834 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5561,7 +5561,7 @@ "category": "Message", "code": 95109 }, - "Wrap this object literal with parentheses": { + "Wrap the following body with parentheses which should be an object literal": { "category": "Message", "code": 95110 }, diff --git a/src/compiler/factoryPublic.ts b/src/compiler/factoryPublic.ts index 8ffc3ee83918e..0360e61745dba 100644 --- a/src/compiler/factoryPublic.ts +++ b/src/compiler/factoryPublic.ts @@ -2042,6 +2042,25 @@ namespace ts { : node; } + export function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration { + switch (declaration.kind) { + case SyntaxKind.FunctionDeclaration: + return createFunctionDeclaration(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.MethodDeclaration: + return createMethod(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.questionToken, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.GetAccessor: + return createGetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, declaration.type, body); + case SyntaxKind.SetAccessor: + return createSetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, body); + case SyntaxKind.Constructor: + return createConstructor(declaration.decorators, declaration.modifiers, declaration.parameters, body); + case SyntaxKind.FunctionExpression: + return createFunctionExpression(declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); + case SyntaxKind.ArrowFunction: + return createArrowFunction(declaration.modifiers, declaration.typeParameters, declaration.parameters, declaration.type, declaration.equalsGreaterThanToken, body); + } + } + export function createClassDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index ad440e561430c..4804bb807b837 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -10,23 +10,25 @@ namespace ts.codefix { Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code ]; - enum FixKind { + enum ProblemKind { MissingReturnStatement, MissingParentheses } interface MissingReturnInfo { - kind: FixKind.MissingReturnStatement; + kind: ProblemKind.MissingReturnStatement; declaration: FunctionLikeDeclaration; expression: Expression; statement: Statement; + commentSource: Node; } interface MissingParenInfo { - kind: FixKind.MissingParentheses; + kind: ProblemKind.MissingParentheses; declaration: ArrowFunction; expression: Expression; statement: Statement; + commentSource: Node; } type Info = MissingReturnInfo | MissingParenInfo; @@ -39,10 +41,10 @@ namespace ts.codefix { const info = getInfo(program.getTypeChecker(), sourceFile, start, errorCode); if (!info) return undefined; - if (info.kind === FixKind.MissingReturnStatement) { + if (info.kind === ProblemKind.MissingReturnStatement) { return append( [getActionForfixAddReturnStatement(context, info.expression, info.statement)], - isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression): undefined); + isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression, info.commentSource): undefined); } else { return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)]; @@ -58,7 +60,7 @@ namespace ts.codefix { break; case fixIdRemoveBlockBodyBrace: if (!isArrowFunction(info.declaration)) return undefined; - removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, /* withParen */ false); + removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, info.commentSource, /* withParen */ false); break; case fixIdWrapTheBlockWithParen: if (!isArrowFunction(info.declaration)) return undefined; @@ -70,25 +72,6 @@ namespace ts.codefix { }), }); - function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration { - switch (declaration.kind) { - case SyntaxKind.FunctionDeclaration: - return createFunctionDeclaration(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); - case SyntaxKind.MethodDeclaration: - return createMethod(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.questionToken, declaration.typeParameters, declaration.parameters, declaration.type, body); - case SyntaxKind.GetAccessor: - return createGetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, declaration.type, body); - case SyntaxKind.SetAccessor: - return createSetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, body); - case SyntaxKind.Constructor: - return createConstructor(declaration.decorators, declaration.modifiers, declaration.parameters, body); - case SyntaxKind.FunctionExpression: - return createFunctionExpression(declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body); - case SyntaxKind.ArrowFunction: - return createArrowFunction(declaration.modifiers, declaration.typeParameters, declaration.parameters, declaration.type, declaration.equalsGreaterThanToken, body); - } - } - function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type, isFunctionType: boolean): Info | undefined { if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; @@ -96,9 +79,10 @@ namespace ts.codefix { if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, firstStatement.expression, expectType, isFunctionType)) { return { declaration, - kind: FixKind.MissingReturnStatement, + kind: ProblemKind.MissingReturnStatement, expression: firstStatement.expression, - statement: firstStatement + statement: firstStatement, + commentSource: firstStatement.expression }; } else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { @@ -106,14 +90,16 @@ namespace ts.codefix { if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { return isArrowFunction(declaration) ? { declaration, - kind: FixKind.MissingParentheses, + kind: ProblemKind.MissingParentheses, expression: node, - statement: firstStatement + statement: firstStatement, + commentSource: firstStatement.statement.expression } : { declaration, - kind: FixKind.MissingReturnStatement, + kind: ProblemKind.MissingReturnStatement, expression: node, - statement: firstStatement + statement: firstStatement, + commentSource: firstStatement.statement.expression }; } } @@ -124,9 +110,10 @@ namespace ts.codefix { if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) { return { declaration, - kind: FixKind.MissingReturnStatement, + kind: ProblemKind.MissingReturnStatement, expression: node, - statement: firstStatement + statement: firstStatement, + commentSource: firstBlockStatement }; } } @@ -183,11 +170,16 @@ namespace ts.codefix { } function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) { + suppressLeadingAndTrailingTrivia(expression); changes.replaceNode(sourceFile, statement, createReturn(expression)); } - function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, withParen: boolean) { - changes.replaceNode(sourceFile, declaration.body, (withParen || needsParentheses(expression)) ? createParen(expression) : expression); + function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, commentSource: Node, withParen: boolean) { + const newBody = (withParen || needsParentheses(expression)) ? createParen(expression) : expression; + suppressLeadingAndTrailingTrivia(commentSource); + copyComments(commentSource, newBody); + + changes.replaceNode(sourceFile, declaration.body, newBody); } function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression) { @@ -199,13 +191,13 @@ namespace ts.codefix { return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement); } - function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, /* withParen */ false)); + function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) { + const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /* withParen */ false)); return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Remove_all_incorrect_body_block_braces); } function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Wrap_this_object_literal_with_parentheses, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses); + return createCodeFixAction(fixId, changes, Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses); } } diff --git a/src/services/refactors/convertParamsToDestructuredObject.ts b/src/services/refactors/convertParamsToDestructuredObject.ts index 803a767761090..dcb0d520f9f87 100644 --- a/src/services/refactors/convertParamsToDestructuredObject.ts +++ b/src/services/refactors/convertParamsToDestructuredObject.ts @@ -491,27 +491,6 @@ namespace ts.refactor.convertParamsToDestructuredObject { } } - function copyComments(sourceNode: Node, targetNode: Node) { - const sourceFile = sourceNode.getSourceFile(); - const text = sourceFile.text; - if (hasLeadingLineBreak(sourceNode, text)) { - copyLeadingComments(sourceNode, targetNode, sourceFile); - } - else { - copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile); - } - copyTrailingComments(sourceNode, targetNode, sourceFile); - } - - function hasLeadingLineBreak(node: Node, text: string) { - const start = node.getFullStart(); - const end = node.getStart(); - for (let i = start; i < end; i++) { - if (text.charCodeAt(i) === CharacterCodes.lineFeed) return true; - } - return false; - } - function getParameterName(paramDeclaration: ValidParameterDeclaration) { return getTextOfIdentifierOrLiteral(paramDeclaration.name); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 090c350496144..91a6a856fedab 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -2250,6 +2250,27 @@ namespace ts { addEmitFlagsRecursively(node, EmitFlags.NoTrailingComments, getLastChild); } + export function copyComments(sourceNode: Node, targetNode: Node) { + const sourceFile = sourceNode.getSourceFile(); + const text = sourceFile.text; + if (hasLeadingLineBreak(sourceNode, text)) { + copyLeadingComments(sourceNode, targetNode, sourceFile); + } + else { + copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile); + } + copyTrailingComments(sourceNode, targetNode, sourceFile); + } + + function hasLeadingLineBreak(node: Node, text: string) { + const start = node.getFullStart(); + const end = node.getStart(); + for (let i = start; i < end; i++) { + if (text.charCodeAt(i) === CharacterCodes.lineFeed) return true; + } + return false; + } + function addEmitFlagsRecursively(node: Node, flag: EmitFlags, getChild: (n: Node) => Node | undefined) { addEmitFlags(node, flag); const child = getChild(node); diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue14.ts b/tests/cases/fourslash/codeFixCorrectReturnValue14.ts index 8951f82993d0b..0f602eb1a139d 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue14.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue14.ts @@ -8,6 +8,6 @@ //// } verify.codeFixAvailable([ - { description: 'Wrap this object literal with parentheses' }, + { description: 'Wrap the following body with parentheses which should be an object literal' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue15.ts b/tests/cases/fourslash/codeFixCorrectReturnValue15.ts index b6ba1824293b3..6b6280cec4a0d 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue15.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue15.ts @@ -7,6 +7,6 @@ //// Foo(() => { bar: '1' }) verify.codeFixAvailable([ - { description: 'Wrap this object literal with parentheses' }, + { description: 'Wrap the following body with parentheses which should be an object literal' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue16.ts b/tests/cases/fourslash/codeFixCorrectReturnValue16.ts index 1a8e685ab6f30..bacb9a373b2e0 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue16.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue16.ts @@ -8,6 +8,6 @@ //// Foo(() => { bar: '1' }) verify.codeFixAvailable([ - { description: 'Wrap this object literal with parentheses' }, + { description: 'Wrap the following body with parentheses which should be an object literal' }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue19.ts b/tests/cases/fourslash/codeFixCorrectReturnValue19.ts index 00ef70a3a1840..a8726a5ed6f17 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue19.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue19.ts @@ -14,7 +14,7 @@ //// var x = { bar: '1' }} />; verify.codeFixAvailable([ - { description: 'Wrap this object literal with parentheses' }, + { description: 'Wrap the following body with parentheses which should be an object literal' }, { description: `Infer type of 'props' from usage` }, { description: 'Remove unused label' }, ]); diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue24.ts b/tests/cases/fourslash/codeFixCorrectReturnValue24.ts new file mode 100644 index 0000000000000..89f6c780b79b4 --- /dev/null +++ b/tests/cases/fourslash/codeFixCorrectReturnValue24.ts @@ -0,0 +1,12 @@ +/// + +//// function Foo (a: () => number) { a() } +//// Foo(() => { /* leading */ 1 /* trailing */ }) + +verify.codeFix({ + description: "Add a return statement", + index: 0, + newFileContent: + `function Foo (a: () => number) { a() } +Foo(() => { /* leading */ return 1 /* trailing */ })` +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue25.ts b/tests/cases/fourslash/codeFixCorrectReturnValue25.ts new file mode 100644 index 0000000000000..205863efd4b19 --- /dev/null +++ b/tests/cases/fourslash/codeFixCorrectReturnValue25.ts @@ -0,0 +1,12 @@ +/// + +//// function Foo (a: () => number) { a() } +//// Foo(() => { /* leading */ 1 /* trailing */ }) + +verify.codeFix({ + description: "Remove block body braces", + index: 1, + newFileContent: + `function Foo (a: () => number) { a() } +Foo(() => /* leading */ 1 /* trailing */)` +}) \ No newline at end of file From 175cf4ea9f1f1b24a8cc312c67d3e41095a4e882 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 26 Mar 2020 23:02:00 +0800 Subject: [PATCH 19/20] Support semi --- src/services/codefixes/returnValueCorrect.ts | 7 +++++- .../fourslash/codeFixCorrectReturnValue24.ts | 2 +- .../fourslash/codeFixCorrectReturnValue25.ts | 2 +- .../fourslash/codeFixCorrectReturnValue26.ts | 23 +++++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/codeFixCorrectReturnValue26.ts diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index 4804bb807b837..947b9933e302e 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -171,7 +171,12 @@ namespace ts.codefix { function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) { suppressLeadingAndTrailingTrivia(expression); - changes.replaceNode(sourceFile, statement, createReturn(expression)); + const probablyNeedSemi = probablyUsesSemicolons(sourceFile); + changes.replaceNode(sourceFile, statement, createReturn(expression), { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + suffix: probablyNeedSemi ? ";" : undefined + }); } function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, commentSource: Node, withParen: boolean) { diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue24.ts b/tests/cases/fourslash/codeFixCorrectReturnValue24.ts index 89f6c780b79b4..6cc9e52e4d0d9 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue24.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue24.ts @@ -7,6 +7,6 @@ verify.codeFix({ description: "Add a return statement", index: 0, newFileContent: - `function Foo (a: () => number) { a() } +`function Foo (a: () => number) { a() } Foo(() => { /* leading */ return 1 /* trailing */ })` }) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue25.ts b/tests/cases/fourslash/codeFixCorrectReturnValue25.ts index 205863efd4b19..3d7f750367305 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue25.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue25.ts @@ -7,6 +7,6 @@ verify.codeFix({ description: "Remove block body braces", index: 1, newFileContent: - `function Foo (a: () => number) { a() } +`function Foo (a: () => number) { a() } Foo(() => /* leading */ 1 /* trailing */)` }) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue26.ts b/tests/cases/fourslash/codeFixCorrectReturnValue26.ts new file mode 100644 index 0000000000000..36f9ff9fa3b13 --- /dev/null +++ b/tests/cases/fourslash/codeFixCorrectReturnValue26.ts @@ -0,0 +1,23 @@ +/// +//// interface A { +//// bar: string; +//// } +//// +//// function Foo (a: () => A) { a(); } +//// Foo(() => { +//// { bar: '123'; } +//// }) + +verify.codeFix({ + description: "Add a return statement", + index: 0, + newFileContent: +`interface A { + bar: string; +} + +function Foo (a: () => A) { a(); } +Foo(() => { + return { bar: '123' }; +})` +}) From 5d8355c6b1e3fca0d62ab41c7f5924816f2a717b Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 26 Mar 2020 23:48:17 +0800 Subject: [PATCH 20/20] make helper internal --- src/compiler/factoryPublic.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/factoryPublic.ts b/src/compiler/factoryPublic.ts index a952041cbed40..f0aae0daf938b 100644 --- a/src/compiler/factoryPublic.ts +++ b/src/compiler/factoryPublic.ts @@ -2057,6 +2057,7 @@ namespace ts { : node; } + /* @internal */ export function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration { switch (declaration.kind) { case SyntaxKind.FunctionDeclaration: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy