From 25bba41fc2ea07e56962ef22bc8a011715f05e66 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 3 Nov 2021 21:22:35 +0000 Subject: [PATCH] Cherry-pick PR #46628 into release-4.5 Component commits: 9f9f3edc60 fix(46615): remove useless assertion. change error suggestion for rest params --- src/compiler/checker.ts | 5 +-- .../codefixes/addNameToNamelessParameter.ts | 10 +++--- .../noImplicitAnyNamelessParameter.errors.txt | 28 ++++++++------- .../noImplicitAnyNamelessParameter.js | 7 ++-- .../noImplicitAnyNamelessParameter.symbols | 35 +++++++++++-------- .../noImplicitAnyNamelessParameter.types | 17 +++++---- .../noImplicitAnyNamelessParameter.ts | 7 ++-- ...rNames.ts => codeFixAddParameterNames1.ts} | 0 .../fourslash/codeFixAddParameterNames2.ts | 6 ++++ .../fourslash/codeFixAddParameterNames3.ts | 6 ++++ 10 files changed, 75 insertions(+), 46 deletions(-) rename tests/cases/fourslash/{codeFixAddParameterNames.ts => codeFixAddParameterNames1.ts} (100%) create mode 100644 tests/cases/fourslash/codeFixAddParameterNames2.ts create mode 100644 tests/cases/fourslash/codeFixAddParameterNames3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d1bf23546c56..67bd63fc2cfc6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21204,9 +21204,10 @@ namespace ts { (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && param.parent.parameters.indexOf(param) > -1 && (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || - param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind))) { + param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind))) { const newName = "arg" + param.parent.parameters.indexOf(param); - errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, declarationNameToString(param.name)); + const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); + errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); return; } diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? diff --git a/src/services/codefixes/addNameToNamelessParameter.ts b/src/services/codefixes/addNameToNamelessParameter.ts index 07bc1bea7e3c6..bd53c23743239 100644 --- a/src/services/codefixes/addNameToNamelessParameter.ts +++ b/src/services/codefixes/addNameToNamelessParameter.ts @@ -14,24 +14,24 @@ namespace ts.codefix { function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const token = getTokenAtPosition(sourceFile, pos); - if (!isIdentifier(token)) { - return Debug.fail("add-name-to-nameless-parameter operates on identifiers, but got a " + Debug.formatSyntaxKind(token.kind)); - } const param = token.parent; if (!isParameter(param)) { return Debug.fail("Tried to add a parameter name to a non-parameter: " + Debug.formatSyntaxKind(token.kind)); } + const i = param.parent.parameters.indexOf(param); Debug.assert(!param.type, "Tried to add a parameter name to a parameter that already had one."); Debug.assert(i > -1, "Parameter not found in parent parameter list."); + + const typeNode = factory.createTypeReferenceNode(param.name as Identifier, /*typeArguments*/ undefined); const replacement = factory.createParameterDeclaration( /*decorators*/ undefined, param.modifiers, param.dotDotDotToken, "arg" + i, param.questionToken, - factory.createTypeReferenceNode(token, /*typeArguments*/ undefined), + param.dotDotDotToken ? factory.createArrayTypeNode(typeNode) : typeNode, param.initializer); - changeTracker.replaceNode(sourceFile, token, replacement); + changeTracker.replaceNode(sourceFile, param, replacement); } } diff --git a/tests/baselines/reference/noImplicitAnyNamelessParameter.errors.txt b/tests/baselines/reference/noImplicitAnyNamelessParameter.errors.txt index 9dc95461d63c1..c93dd533a1ef5 100644 --- a/tests/baselines/reference/noImplicitAnyNamelessParameter.errors.txt +++ b/tests/baselines/reference/noImplicitAnyNamelessParameter.errors.txt @@ -1,26 +1,30 @@ -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(2,17): error TS7051: Parameter has a name but no type. Did you mean 'arg0: string'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(2,25): error TS7051: Parameter has a name but no type. Did you mean 'arg1: C'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(3,19): error TS7051: Parameter has a name but no type. Did you mean 'arg0: C'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(3,22): error TS7051: Parameter has a name but no type. Did you mean 'arg1: number'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,20): error TS7051: Parameter has a name but no type. Did you mean 'arg0: boolean'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,29): error TS7051: Parameter has a name but no type. Did you mean 'arg1: C'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,32): error TS7051: Parameter has a name but no type. Did you mean 'arg2: object'? -tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,40): error TS7051: Parameter has a name but no type. Did you mean 'arg3: undefined'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(2,20): error TS7051: Parameter has a name but no type. Did you mean 'arg0: string[]'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(3,17): error TS7051: Parameter has a name but no type. Did you mean 'arg0: string'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(3,25): error TS7051: Parameter has a name but no type. Did you mean 'arg1: C'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,19): error TS7051: Parameter has a name but no type. Did you mean 'arg0: C'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(4,22): error TS7051: Parameter has a name but no type. Did you mean 'arg1: number'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(5,20): error TS7051: Parameter has a name but no type. Did you mean 'arg0: boolean'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(5,29): error TS7051: Parameter has a name but no type. Did you mean 'arg1: C'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(5,32): error TS7051: Parameter has a name but no type. Did you mean 'arg2: object'? +tests/cases/compiler/noImplicitAnyNamelessParameter.ts(5,40): error TS7051: Parameter has a name but no type. Did you mean 'arg3: undefined'? -==== tests/cases/compiler/noImplicitAnyNamelessParameter.ts (8 errors) ==== +==== tests/cases/compiler/noImplicitAnyNamelessParameter.ts (9 errors) ==== class C { } - declare var x: (string, C) => void; + declare var a: { m(...string): void } + ~~~~~~~~~ +!!! error TS7051: Parameter has a name but no type. Did you mean 'arg0: string[]'? + declare var b: (string, C) => void; ~~~~~~ !!! error TS7051: Parameter has a name but no type. Did you mean 'arg0: string'? ~ !!! error TS7051: Parameter has a name but no type. Did you mean 'arg1: C'? - declare var y: { (C, number): void }; + declare var c: { (C, number): void }; ~ !!! error TS7051: Parameter has a name but no type. Did you mean 'arg0: C'? ~~~~~~ !!! error TS7051: Parameter has a name but no type. Did you mean 'arg1: number'? - declare var z: { m(boolean, C, object, undefined): void } + declare var d: { m(boolean, C, object, undefined): void } ~~~~~~~ !!! error TS7051: Parameter has a name but no type. Did you mean 'arg0: boolean'? ~ diff --git a/tests/baselines/reference/noImplicitAnyNamelessParameter.js b/tests/baselines/reference/noImplicitAnyNamelessParameter.js index 39d7e644578b3..5fabc25b94043 100644 --- a/tests/baselines/reference/noImplicitAnyNamelessParameter.js +++ b/tests/baselines/reference/noImplicitAnyNamelessParameter.js @@ -1,8 +1,9 @@ //// [noImplicitAnyNamelessParameter.ts] class C { } -declare var x: (string, C) => void; -declare var y: { (C, number): void }; -declare var z: { m(boolean, C, object, undefined): void } +declare var a: { m(...string): void } +declare var b: (string, C) => void; +declare var c: { (C, number): void }; +declare var d: { m(boolean, C, object, undefined): void } // note: null and void do not parse correctly without a preceding parameter name diff --git a/tests/baselines/reference/noImplicitAnyNamelessParameter.symbols b/tests/baselines/reference/noImplicitAnyNamelessParameter.symbols index 2a22f5389d6bb..1662ce08e4693 100644 --- a/tests/baselines/reference/noImplicitAnyNamelessParameter.symbols +++ b/tests/baselines/reference/noImplicitAnyNamelessParameter.symbols @@ -2,23 +2,28 @@ class C { } >C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 0, 0)) -declare var x: (string, C) => void; ->x : Symbol(x, Decl(noImplicitAnyNamelessParameter.ts, 1, 11)) ->string : Symbol(string, Decl(noImplicitAnyNamelessParameter.ts, 1, 16)) ->C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 1, 23)) +declare var a: { m(...string): void } +>a : Symbol(a, Decl(noImplicitAnyNamelessParameter.ts, 1, 11)) +>m : Symbol(m, Decl(noImplicitAnyNamelessParameter.ts, 1, 16)) +>string : Symbol(string, Decl(noImplicitAnyNamelessParameter.ts, 1, 19)) -declare var y: { (C, number): void }; ->y : Symbol(y, Decl(noImplicitAnyNamelessParameter.ts, 2, 11)) ->C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 2, 18)) ->number : Symbol(number, Decl(noImplicitAnyNamelessParameter.ts, 2, 20)) +declare var b: (string, C) => void; +>b : Symbol(b, Decl(noImplicitAnyNamelessParameter.ts, 2, 11)) +>string : Symbol(string, Decl(noImplicitAnyNamelessParameter.ts, 2, 16)) +>C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 2, 23)) -declare var z: { m(boolean, C, object, undefined): void } ->z : Symbol(z, Decl(noImplicitAnyNamelessParameter.ts, 3, 11)) ->m : Symbol(m, Decl(noImplicitAnyNamelessParameter.ts, 3, 16)) ->boolean : Symbol(boolean, Decl(noImplicitAnyNamelessParameter.ts, 3, 19)) ->C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 3, 27)) ->object : Symbol(object, Decl(noImplicitAnyNamelessParameter.ts, 3, 30)) ->undefined : Symbol(undefined, Decl(noImplicitAnyNamelessParameter.ts, 3, 38)) +declare var c: { (C, number): void }; +>c : Symbol(c, Decl(noImplicitAnyNamelessParameter.ts, 3, 11)) +>C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 3, 18)) +>number : Symbol(number, Decl(noImplicitAnyNamelessParameter.ts, 3, 20)) + +declare var d: { m(boolean, C, object, undefined): void } +>d : Symbol(d, Decl(noImplicitAnyNamelessParameter.ts, 4, 11)) +>m : Symbol(m, Decl(noImplicitAnyNamelessParameter.ts, 4, 16)) +>boolean : Symbol(boolean, Decl(noImplicitAnyNamelessParameter.ts, 4, 19)) +>C : Symbol(C, Decl(noImplicitAnyNamelessParameter.ts, 4, 27)) +>object : Symbol(object, Decl(noImplicitAnyNamelessParameter.ts, 4, 30)) +>undefined : Symbol(undefined, Decl(noImplicitAnyNamelessParameter.ts, 4, 38)) // note: null and void do not parse correctly without a preceding parameter name diff --git a/tests/baselines/reference/noImplicitAnyNamelessParameter.types b/tests/baselines/reference/noImplicitAnyNamelessParameter.types index 7ab5cdcc4bdb7..bd274700b7e60 100644 --- a/tests/baselines/reference/noImplicitAnyNamelessParameter.types +++ b/tests/baselines/reference/noImplicitAnyNamelessParameter.types @@ -2,18 +2,23 @@ class C { } >C : C -declare var x: (string, C) => void; ->x : (string: any, C: any) => void +declare var a: { m(...string): void } +>a : { m(...string: any[]): void; } +>m : (...string: any[]) => void +>string : any[] + +declare var b: (string, C) => void; +>b : (string: any, C: any) => void >string : any >C : any -declare var y: { (C, number): void }; ->y : (C: any, number: any) => void +declare var c: { (C, number): void }; +>c : (C: any, number: any) => void >C : any >number : any -declare var z: { m(boolean, C, object, undefined): void } ->z : { m(boolean: any, C: any, object: any, undefined: any): void; } +declare var d: { m(boolean, C, object, undefined): void } +>d : { m(boolean: any, C: any, object: any, undefined: any): void; } >m : (boolean: any, C: any, object: any, undefined: any) => void >boolean : any >C : any diff --git a/tests/cases/compiler/noImplicitAnyNamelessParameter.ts b/tests/cases/compiler/noImplicitAnyNamelessParameter.ts index 6206a5e68ad24..aa98a725bd687 100644 --- a/tests/cases/compiler/noImplicitAnyNamelessParameter.ts +++ b/tests/cases/compiler/noImplicitAnyNamelessParameter.ts @@ -1,6 +1,7 @@ // @noImplicitAny: true class C { } -declare var x: (string, C) => void; -declare var y: { (C, number): void }; -declare var z: { m(boolean, C, object, undefined): void } +declare var a: { m(...string): void } +declare var b: (string, C) => void; +declare var c: { (C, number): void }; +declare var d: { m(boolean, C, object, undefined): void } // note: null and void do not parse correctly without a preceding parameter name diff --git a/tests/cases/fourslash/codeFixAddParameterNames.ts b/tests/cases/fourslash/codeFixAddParameterNames1.ts similarity index 100% rename from tests/cases/fourslash/codeFixAddParameterNames.ts rename to tests/cases/fourslash/codeFixAddParameterNames1.ts diff --git a/tests/cases/fourslash/codeFixAddParameterNames2.ts b/tests/cases/fourslash/codeFixAddParameterNames2.ts new file mode 100644 index 0000000000000..31e26358aebc4 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddParameterNames2.ts @@ -0,0 +1,6 @@ +/// + +// @noImplicitAny: true +////type Rest = ([|...number|]) => void; + +verify.rangeAfterCodeFix("...arg0: number[]"); diff --git a/tests/cases/fourslash/codeFixAddParameterNames3.ts b/tests/cases/fourslash/codeFixAddParameterNames3.ts new file mode 100644 index 0000000000000..465471e11287f --- /dev/null +++ b/tests/cases/fourslash/codeFixAddParameterNames3.ts @@ -0,0 +1,6 @@ +/// + +// @noImplicitAny: true +////type Rest = ([|public string|]) => void; + +verify.rangeAfterCodeFix("public arg0: string");