From 627c95e3f5fca9499c174655abc1292e8a305a11 Mon Sep 17 00:00:00 2001 From: Markus Johnsson Date: Wed, 28 Feb 2018 08:55:07 +0100 Subject: [PATCH 01/27] Infer parameter names and types when applying Delcare Method codefix (#22180) --- src/services/codefixes/fixAddMissingMember.ts | 10 +++---- src/services/codefixes/helpers.ts | 21 +++++++++++---- .../fourslash/codeFixAddMissingMember9.ts | 24 +++++++++++++++++ .../codeFixUndeclaredAcrossFiles1.ts | 7 ++++- .../codeFixUndeclaredAcrossFiles3.ts | 26 +++++++++++++++++++ .../codeFixUndeclaredInStaticMethod.ts | 14 +++++----- .../fourslash/codeFixUndeclaredMethod.ts | 6 ++--- 7 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 tests/cases/fourslash/codeFixAddMissingMember9.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 7dbbc39843f..2adbfd1dd85 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -31,7 +31,7 @@ namespace ts.codefix { // Always prefer to add a method declaration if possible. if (call) { - addMethodDeclaration(changes, classDeclarationSourceFile, classDeclaration, token, call, makeStatic, inJs); + addMethodDeclaration(context, changes, classDeclarationSourceFile, classDeclaration, token, call, makeStatic, inJs); } else { if (inJs) { @@ -181,14 +181,14 @@ namespace ts.codefix { return { description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]), changes, fixId: undefined }; } - function getActionForMethodDeclaration(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean): CodeFixAction | undefined { + function getActionForMethodDeclaration(context: CodeFixContextBase, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean): CodeFixAction | undefined { const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0), [token.text]); - const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(t, classDeclarationSourceFile, classDeclaration, token, callExpression, makeStatic, inJs)); + const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, classDeclarationSourceFile, classDeclaration, token, callExpression, makeStatic, inJs)); return { description, changes, fixId }; } - function addMethodDeclaration(changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean) { - const methodDeclaration = createMethodFromCallExpression(callExpression, token.text, inJs, makeStatic); + function addMethodDeclaration(context: CodeFixContextBase, changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean) { + const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic); changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration); } } diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 6a45c66ca81..f746a08561c 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -107,7 +107,18 @@ namespace ts.codefix { return nodes && createNodeArray(nodes.map(getSynthesizedDeepClone)); } - export function createMethodFromCallExpression({ typeArguments, arguments: args }: CallExpression, methodName: string, inJs: boolean, makeStatic: boolean): MethodDeclaration { + export function createMethodFromCallExpression(context: CodeFixContextBase, { typeArguments, arguments: args }: CallExpression, methodName: string, inJs: boolean, makeStatic: boolean): MethodDeclaration { + const checker = context.program.getTypeChecker(); + const types = map(args, + (arg) => { + let type = checker.getTypeAtLocation(arg); + // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" + type = checker.getBaseTypeOfLiteralType(type); + return checker.typeToTypeNode(type); + }); + const names = map(args, (arg) => + isIdentifier(arg) ? arg.text : + isPropertyAccessExpression(arg) ? arg.name.text : undefined); return createMethod( /*decorators*/ undefined, /*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined, @@ -116,12 +127,12 @@ namespace ts.codefix { /*questionToken*/ undefined, /*typeParameters*/ inJs ? undefined : map(typeArguments, (_, i) => createTypeParameterDeclaration(CharacterCodes.T + typeArguments.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)), - /*parameters*/ createDummyParameters(args.length, /*names*/ undefined, /*minArgumentCount*/ undefined, inJs), + /*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs), /*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword), createStubbedMethodBody()); } - function createDummyParameters(argCount: number, names: string[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] { + function createDummyParameters(argCount: number, names: string[] | undefined, types: TypeNode[], minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] { const parameters: ParameterDeclaration[] = []; for (let i = 0; i < argCount; i++) { const newParameter = createParameter( @@ -130,7 +141,7 @@ namespace ts.codefix { /*dotDotDotToken*/ undefined, /*name*/ names && names[i] || `arg${i}`, /*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined, - /*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*type*/ inJs ? undefined : types && types[i] || createKeywordTypeNode(SyntaxKind.AnyKeyword), /*initializer*/ undefined); parameters.push(newParameter); } @@ -157,7 +168,7 @@ namespace ts.codefix { const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0); const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.name); - const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, minArgumentCount, /*inJs*/ false); + const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, /* types */ undefined, minArgumentCount, /*inJs*/ false); if (someSigHasRestParameter) { const anyArrayType = createArrayTypeNode(createKeywordTypeNode(SyntaxKind.AnyKeyword)); diff --git a/tests/cases/fourslash/codeFixAddMissingMember9.ts b/tests/cases/fourslash/codeFixAddMissingMember9.ts new file mode 100644 index 00000000000..afe401f350b --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember9.ts @@ -0,0 +1,24 @@ +/// + +////class C { +//// z: boolean = true; +//// method() { +//// const x = 0; +//// this.y(x, "a", this.z); +//// } +////} + +verify.codeFixAll({ + fixId: "addMissingMember", + newFileContent: +`class C { + y(x: number, arg1: string, z: boolean): any { + throw new Error("Method not implemented."); + } + z: boolean = true; + method() { + const x = 0; + this.y(x, "a", this.z); + } +}`, +}); diff --git a/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts index a946b60f173..5d494e877e3 100644 --- a/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts +++ b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts @@ -10,6 +10,7 @@ //// let c = new X.C; //// c.m1(); //// c.y = {}; +//// c.m2(c); // @Filename: f1.ts //// export class C {[| @@ -21,14 +22,18 @@ verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); +verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.rangeIs(` + m2(c: C): any { + throw new Error("Method not implemented."); + } y: {}; m1(): any { throw new Error("Method not implemented."); } static x: any; - static m0(arg0: any, arg1: any, arg2: any): any { + static m0(arg0: number, arg1: string, arg2: undefined[]): any { throw new Error("Method not implemented."); } `); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts new file mode 100644 index 00000000000..2b07493f923 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts @@ -0,0 +1,26 @@ +/// + +// @allowJs: true +// @checkJs: true + +// @Filename: f3.ts +//// import { C } from "./f1"; +//// import { D } from "./f2"; +//// const c = new C(); +//// c.m0(new D()); + +// @Filename: f2.ts +//// export class D { } + +// @Filename: f1.ts +//// export class C {[| +//// |]x: number; +//// } + +verify.getAndApplyCodeFix(/*errorCode*/ undefined, 0); + +verify.rangeIs(` + m0(arg0: D): any { + throw new Error("Method not implemented."); + } +`); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredInStaticMethod.ts b/tests/cases/fourslash/codeFixUndeclaredInStaticMethod.ts index 0bd4ac3a879..4552f204df1 100644 --- a/tests/cases/fourslash/codeFixUndeclaredInStaticMethod.ts +++ b/tests/cases/fourslash/codeFixUndeclaredInStaticMethod.ts @@ -13,7 +13,7 @@ verify.codeFix({ description: "Declare static method 'm1'", index: 0, newRangeContent: ` - static m1(arg0: any, arg1: any, arg2: any): any { + static m1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } `, @@ -23,10 +23,10 @@ verify.codeFix({ description: "Declare static method 'm2'", index: 0, newRangeContent: ` - static m2(arg0: any, arg1: any): any { + static m2(arg0: number, arg1: number): any { throw new Error("Method not implemented."); } - static m1(arg0: any, arg1: any, arg2: any): any { + static m1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } `, @@ -37,10 +37,10 @@ verify.codeFix({ index: 0, newRangeContent: ` static prop1: number; - static m2(arg0: any, arg1: any): any { + static m2(arg0: number, arg1: number): any { throw new Error("Method not implemented."); } - static m1(arg0: any, arg1: any, arg2: any): any { + static m1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } `, @@ -52,10 +52,10 @@ verify.codeFix({ newRangeContent: ` static prop2: string; static prop1: number; - static m2(arg0: any, arg1: any): any { + static m2(arg0: number, arg1: number): any { throw new Error("Method not implemented."); } - static m1(arg0: any, arg1: any, arg2: any): any { + static m1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } `, diff --git a/tests/cases/fourslash/codeFixUndeclaredMethod.ts b/tests/cases/fourslash/codeFixUndeclaredMethod.ts index 70ed58b995b..795b7052a68 100644 --- a/tests/cases/fourslash/codeFixUndeclaredMethod.ts +++ b/tests/cases/fourslash/codeFixUndeclaredMethod.ts @@ -14,7 +14,7 @@ verify.codeFix({ description: "Declare method 'foo1'", index: 0, newRangeContent: ` - foo1(arg0: any, arg1: any, arg2: any): any { + foo1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } `, @@ -27,7 +27,7 @@ verify.codeFix({ foo2(): any { throw new Error("Method not implemented."); } - foo1(arg0: any, arg1: any, arg2: any): any { + foo1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } ` @@ -43,7 +43,7 @@ verify.codeFix({ foo2(): any { throw new Error("Method not implemented."); } - foo1(arg0: any, arg1: any, arg2: any): any { + foo1(arg0: number, arg1: number, arg2: number): any { throw new Error("Method not implemented."); } ` From 67eb6fc85920b8443bc8138eccd39224462930fc Mon Sep 17 00:00:00 2001 From: Markus Johnsson Date: Wed, 28 Feb 2018 12:07:41 +0100 Subject: [PATCH 02/27] Added more tests for #22180 --- .../codeFixUndeclaredMethodFunctionArgs.ts | 31 +++++++++++++++++++ ...odeFixUndeclaredMethodObjectLiteralArgs.ts | 17 ++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/cases/fourslash/codeFixUndeclaredMethodFunctionArgs.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredMethodObjectLiteralArgs.ts diff --git a/tests/cases/fourslash/codeFixUndeclaredMethodFunctionArgs.ts b/tests/cases/fourslash/codeFixUndeclaredMethodFunctionArgs.ts new file mode 100644 index 00000000000..1c06cfc3afd --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredMethodFunctionArgs.ts @@ -0,0 +1,31 @@ +/// + +//// class A {[| +//// |]constructor() { +//// this.foo1(() => 1, () => "2", () => false); +//// this.foo2((a: number) => a, (b: string) => b, (c: boolean) => c); +//// } +//// } + +verify.codeFix({ + description: "Declare method 'foo1'", + index: 0, + newRangeContent: ` + foo1(arg0: () => number, arg1: () => string, arg2: () => boolean): any { + throw new Error("Method not implemented."); + } + `, +}); + +verify.codeFix({ + description: "Declare method 'foo2'", + index: 0, + newRangeContent: ` + foo2(arg0: (a: number) => number, arg1: (b: string) => string, arg2: (c: boolean) => boolean): any { + throw new Error("Method not implemented."); + } + foo1(arg0: () => number, arg1: () => string, arg2: () => boolean): any { + throw new Error("Method not implemented."); + } + ` +}); diff --git a/tests/cases/fourslash/codeFixUndeclaredMethodObjectLiteralArgs.ts b/tests/cases/fourslash/codeFixUndeclaredMethodObjectLiteralArgs.ts new file mode 100644 index 00000000000..bd434cf9d9d --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredMethodObjectLiteralArgs.ts @@ -0,0 +1,17 @@ +/// + +//// class A {[| +//// |]constructor() { +//// this.foo1(null, {}, { a: 1, b: "2"}); +//// } +//// } + +verify.codeFix({ + description: "Declare method 'foo1'", + index: 0, + newRangeContent: ` + foo1(arg0: null, arg1: {}, arg2: { a: number; b: string; }): any { + throw new Error("Method not implemented."); + } + ` +}); From 1e058cd1d7cce51283b4e60bd21475daf2a0140b Mon Sep 17 00:00:00 2001 From: Markus Johnsson Date: Sat, 3 Mar 2018 06:58:47 +0100 Subject: [PATCH 03/27] Remove parens from single parameter arrow functions --- src/services/codefixes/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index f746a08561c..e09df4b379a 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -110,13 +110,13 @@ namespace ts.codefix { export function createMethodFromCallExpression(context: CodeFixContextBase, { typeArguments, arguments: args }: CallExpression, methodName: string, inJs: boolean, makeStatic: boolean): MethodDeclaration { const checker = context.program.getTypeChecker(); const types = map(args, - (arg) => { + arg => { let type = checker.getTypeAtLocation(arg); // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" type = checker.getBaseTypeOfLiteralType(type); return checker.typeToTypeNode(type); }); - const names = map(args, (arg) => + const names = map(args, arg => isIdentifier(arg) ? arg.text : isPropertyAccessExpression(arg) ? arg.name.text : undefined); return createMethod( From 8bc92e4a6363804436dba0dc37b33b1d862019bd Mon Sep 17 00:00:00 2001 From: Markus Johnsson Date: Sun, 10 Jun 2018 19:58:32 +0200 Subject: [PATCH 04/27] Update test to reflect new behavior --- tests/cases/fourslash/codeFixAddMissingMember9.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/cases/fourslash/codeFixAddMissingMember9.ts b/tests/cases/fourslash/codeFixAddMissingMember9.ts index afe401f350b..b583cd28e9a 100644 --- a/tests/cases/fourslash/codeFixAddMissingMember9.ts +++ b/tests/cases/fourslash/codeFixAddMissingMember9.ts @@ -10,15 +10,16 @@ verify.codeFixAll({ fixId: "addMissingMember", + fixAllDescription: "Add all missing members", newFileContent: `class C { - y(x: number, arg1: string, z: boolean): any { - throw new Error("Method not implemented."); - } z: boolean = true; method() { const x = 0; this.y(x, "a", this.z); } + y(x: number, arg1: string, z: boolean): any { + throw new Error("Method not implemented."); + } }`, }); From f0c52a454819528a1e019f96131a94b1079f5c0a Mon Sep 17 00:00:00 2001 From: Markus Johnsson Date: Tue, 19 Jun 2018 13:21:07 +0200 Subject: [PATCH 05/27] Accept baseline --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a9fe9a32556..eaac2305bc7 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -11625,7 +11625,7 @@ declare namespace ts.codefix { * @returns Empty string iff there are no member insertions. */ function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: ReadonlyArray, checker: TypeChecker, preferences: UserPreferences, out: (node: ClassElement) => void): void; - function createMethodFromCallExpression({ typeArguments, arguments: args, parent: parent }: CallExpression, methodName: string, inJs: boolean, makeStatic: boolean, preferences: UserPreferences): MethodDeclaration; + function createMethodFromCallExpression(context: CodeFixContextBase, { typeArguments, arguments: args, parent: parent }: CallExpression, methodName: string, inJs: boolean, makeStatic: boolean, preferences: UserPreferences): MethodDeclaration; } declare namespace ts.codefix { } From d41b65756e64ccab5792496284e9cfc766b5b25e Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Tue, 19 Jun 2018 06:50:17 -0700 Subject: [PATCH 06/27] Update user baselines (#25070) --- tests/baselines/reference/user/TypeScript-Node-Starter.log | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/baselines/reference/user/TypeScript-Node-Starter.log b/tests/baselines/reference/user/TypeScript-Node-Starter.log index affbd99af1e..9a0b3b00726 100644 --- a/tests/baselines/reference/user/TypeScript-Node-Starter.log +++ b/tests/baselines/reference/user/TypeScript-Node-Starter.log @@ -1,7 +1,5 @@ Exit Code: 1 Standard output: -node_modules/@types/jquery/index.d.ts(6366,66): error TS2344: Type '"timeout" | "onreadystatechange" | "responseType" | "withCredentials" | "msCaching"' does not satisfy the constraint '"abort" | "open" | "timeout" | "send" | "DONE" | "response" | "getAllResponseHeaders" | "getRespo...'. - Type '"msCaching"' is not assignable to type '"abort" | "open" | "timeout" | "send" | "DONE" | "response" | "getAllResponseHeaders" | "getRespo...'. node_modules/@types/passport-facebook/index.d.ts(50,31): error TS2689: Cannot extend an interface 'passport.Strategy'. Did you mean 'implements'? From 03fff50fa40882a18a4526e33478543b5a49d959 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 19 Jun 2018 10:14:47 -0700 Subject: [PATCH 07/27] Simplify getJSDocCommentAndTags (#24997) Previously, getJSDocCommentAndTags could recur up to four times if any of four predicates matched. However, to avoid duplicates, the predicates have been tuned to be mutually exclusive, which means that the recursion can be turned into a while loop. The while loop is much simpler and safer, since it is guaranteed to only walk up the tree one time. In addition, the extra check that adds jsdoc from initializers only runs once, before the loop, further reducing the opportunity for duplicate jsdocs. I thought about further simplifying the code that gets the next node to check, but to know when to stop the loop, I'd need a predicate that is as complicated as the code in `getNextJSDocCommentLocation`, so I kept the existing code, just reordering it for compactness. --- src/compiler/utilities.ts | 78 +++++++++---------- tests/cases/fourslash/commentsClassMembers.ts | 8 +- .../cases/fourslash/commentsCommentParsing.ts | 6 +- .../fourslash/commentsFunctionExpression.ts | 28 +++---- 4 files changed, 59 insertions(+), 61 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 49769953f02..bb5c232687b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2067,53 +2067,51 @@ namespace ts { export function getJSDocCommentsAndTags(hostNode: Node): ReadonlyArray { let result: (JSDoc | JSDocTag)[] | undefined; - getJSDocCommentsAndTagsWorker(hostNode); - return result || emptyArray; + // Pull parameter comments from declaring function as well + if (isVariableLike(hostNode) && hasInitializer(hostNode) && hasJSDocNodes(hostNode.initializer!)) { + result = addRange(result, (hostNode.initializer as HasJSDoc).jsDoc!); + } - function getJSDocCommentsAndTagsWorker(node: Node): void { - const parent = node.parent; - if (!parent) return; - if (parent.kind === SyntaxKind.PropertyAssignment || parent.kind === SyntaxKind.PropertyDeclaration || getNestedModuleDeclaration(parent)) { - getJSDocCommentsAndTagsWorker(parent); - } - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. - // /** - // * @param {number} name - // * @returns {number} - // */ - // var x = function(name) { return name.length; } - if (parent.parent && (getSingleVariableOfVariableStatement(parent.parent) === node)) { - getJSDocCommentsAndTagsWorker(parent.parent); - } - if (parent.parent && parent.parent.parent && - (getSingleVariableOfVariableStatement(parent.parent.parent) || - getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || - getSourceOfDefaultedAssignment(parent.parent.parent))) { - getJSDocCommentsAndTagsWorker(parent.parent.parent); - } - if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken || - isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken || - node.kind === SyntaxKind.PropertyAccessExpression && node.parent && node.parent.kind === SyntaxKind.ExpressionStatement) { - if (isBinaryExpression(parent)) { - getJSDocCommentsAndTagsWorker(parent.parent); - } - else { - getJSDocCommentsAndTagsWorker(parent); - } + let node: Node | undefined = hostNode; + while (node && node.parent) { + if (hasJSDocNodes(node)) { + result = addRange(result, node.jsDoc!); } - // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration)); + break; } + node = getNextJSDocCommentLocation(node); + } + return result || emptyArray; + } - if (isVariableLike(node) && hasInitializer(node) && node.initializer !== hostNode && hasJSDocNodes(node.initializer!)) { - result = addRange(result, (node.initializer as HasJSDoc).jsDoc); - } - - if (hasJSDocNodes(node)) { - result = addRange(result, node.jsDoc); - } + function getNextJSDocCommentLocation(node: Node) { + const parent = node.parent; + if (parent.kind === SyntaxKind.PropertyAssignment || + parent.kind === SyntaxKind.PropertyDeclaration || + parent.kind === SyntaxKind.ExpressionStatement && node.kind === SyntaxKind.PropertyAccessExpression || + getNestedModuleDeclaration(parent) || + isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken) { + return parent; + } + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. + // /** + // * @param {number} name + // * @returns {number} + // */ + // var x = function(name) { return name.length; } + else if (parent.parent && + (getSingleVariableOfVariableStatement(parent.parent) === node || + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken)) { + return parent.parent; + } + else if (parent.parent && parent.parent.parent && + (getSingleVariableOfVariableStatement(parent.parent.parent) || + getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || + getSourceOfDefaultedAssignment(parent.parent.parent))) { + return parent.parent.parent; } } diff --git a/tests/cases/fourslash/commentsClassMembers.ts b/tests/cases/fourslash/commentsClassMembers.ts index 6b598ab458c..b0ed3e9e48b 100644 --- a/tests/cases/fourslash/commentsClassMembers.ts +++ b/tests/cases/fourslash/commentsClassMembers.ts @@ -572,12 +572,12 @@ verify.quickInfos({ }); goTo.marker('114'); -verify.completionListContains("a", "(property) cWithConstructorProperty.a: number", "this is first parameter a\nmore info about a"); -verify.quickInfoIs("(property) cWithConstructorProperty.a: number", "this is first parameter a\nmore info about a"); +verify.completionListContains("a", "(property) cWithConstructorProperty.a: number", "more info about a\nthis is first parameter a"); +verify.quickInfoIs("(property) cWithConstructorProperty.a: number", "more info about a\nthis is first parameter a"); goTo.marker('115'); -verify.completionListContains("a", "(parameter) a: number", "this is first parameter a\nmore info about a"); -verify.quickInfoIs("(parameter) a: number", "this is first parameter a\nmore info about a"); +verify.completionListContains("a", "(parameter) a: number", "more info about a\nthis is first parameter a"); +verify.quickInfoIs("(parameter) a: number", "more info about a\nthis is first parameter a"); verify.quickInfos({ 116: "this: this", diff --git a/tests/cases/fourslash/commentsCommentParsing.ts b/tests/cases/fourslash/commentsCommentParsing.ts index 6b0c880e9bb..bba86fea299 100644 --- a/tests/cases/fourslash/commentsCommentParsing.ts +++ b/tests/cases/fourslash/commentsCommentParsing.ts @@ -420,7 +420,7 @@ verify.signatureHelp({ marker: "38", docComment: concatDoc, parameterDocComment: verify.quickInfoAt("38aq", "(parameter) bar: string", "is second string"); goTo.marker('39'); -verify.completionListContains("a", "(parameter) a: number", "it is first parameter\nthis is inline comment for a "); +verify.completionListContains("a", "(parameter) a: number", "this is inline comment for a \nit is first parameter"); verify.completionListContains("b", "(parameter) b: number", "this is inline comment for b"); verify.completionListContains("c", "(parameter) c: number", "it is third parameter"); verify.completionListContains("d", "(parameter) d: number", ""); @@ -430,7 +430,7 @@ const jsdocTestTags: ReadonlyArray = [ { name: "param", text: "a it is first parameter" }, { name: "param", text: "c it is third parameter" }, ]; -verify.signatureHelp({ marker: "40", docComment: jsdocTestDocComment, parameterDocComment: "it is first parameter\nthis is inline comment for a ", tags: jsdocTestTags }); +verify.signatureHelp({ marker: "40", docComment: jsdocTestDocComment, parameterDocComment: "this is inline comment for a \nit is first parameter", tags: jsdocTestTags }); verify.quickInfos({ "40q": [ "function jsDocParamTest(a: number, b: number, c: number, d: number): number", @@ -438,7 +438,7 @@ verify.quickInfos({ ], "40aq": [ "(parameter) a: number", - "it is first parameter\nthis is inline comment for a " + "this is inline comment for a \nit is first parameter" ] }); diff --git a/tests/cases/fourslash/commentsFunctionExpression.ts b/tests/cases/fourslash/commentsFunctionExpression.ts index bd9a5c93433..257b8345756 100644 --- a/tests/cases/fourslash/commentsFunctionExpression.ts +++ b/tests/cases/fourslash/commentsFunctionExpression.ts @@ -32,7 +32,7 @@ ////} ////assig/*16*/ned/*17*/(/*18*/"hey"); -verify.quickInfoAt("1", "var lambdaFoo: (a: number, b: number) => number", "lambdaFoo var comment\nthis is lambda comment"); +verify.quickInfoAt("1", "var lambdaFoo: (a: number, b: number) => number", "this is lambda comment\nlambdaFoo var comment"); goTo.marker('2'); verify.completionListContains('a', '(parameter) a: number', 'param a'); @@ -42,18 +42,18 @@ verify.completionListContains('b', '(parameter) b: number', 'param b'); verify.quickInfoAt("3", "var lambddaNoVarComment: (a: number, b: number) => number", "this is lambda multiplication"); goTo.marker('4'); -verify.completionListContains('lambdaFoo', 'var lambdaFoo: (a: number, b: number) => number', 'lambdaFoo var comment\nthis is lambda comment'); +verify.completionListContains('lambdaFoo', 'var lambdaFoo: (a: number, b: number) => number', "this is lambda comment\nlambdaFoo var comment"); verify.completionListContains('lambddaNoVarComment', 'var lambddaNoVarComment: (a: number, b: number) => number', 'this is lambda multiplication'); verify.signatureHelp( { marker: "5", - docComment: "lambdaFoo var comment\nthis is lambda comment", + docComment: "this is lambda comment\nlambdaFoo var comment", parameterDocComment: "param a", }, { marker: "6", - docComment: "lambdaFoo var comment\nthis is lambda comment", + docComment: "this is lambda comment\nlambdaFoo var comment", parameterDocComment: "param b", }, ); @@ -61,31 +61,31 @@ verify.signatureHelp( // no documentation from nested lambda verify.quickInfos({ 7: "function anotherFunc(a: number): string", - 8: ["(local var) lambdaVar: (b: string) => string", "documentation\ninner docs "], + 8: ["(local var) lambdaVar: (b: string) => string", "inner docs \ndocumentation"], 9: ["(parameter) b: string", "inner parameter "], 10: "(local var) localVar: string", 11: "(local var) localVar: string", 12: ["(parameter) b: string", "inner parameter "], - 13: ["(local var) lambdaVar: (b: string) => string", "documentation\ninner docs "], + 13: ["(local var) lambdaVar: (b: string) => string", "inner docs \ndocumentation"], 14: [ "var assigned: (s: string) => number", - "On variable\nSummary on expression" + "Summary on expression\nOn variable" ] }); goTo.marker('15'); -verify.completionListContains('s', '(parameter) s: string', "the first parameter!\nparam on expression\nOn parameter "); -verify.quickInfoAt("16", "var assigned: (s: string) => number", "On variable\nSummary on expression"); +verify.completionListContains('s', '(parameter) s: string', "On parameter \nparam on expression\nthe first parameter!"); +verify.quickInfoAt("16", "var assigned: (s: string) => number", "Summary on expression\nOn variable"); goTo.marker('17'); -verify.completionListContains("assigned", "var assigned: (s: string) => number", "On variable\nSummary on expression"); +verify.completionListContains("assigned", "var assigned: (s: string) => number", "Summary on expression\nOn variable"); verify.signatureHelp({ marker: "18", - docComment: "On variable\nSummary on expression", - parameterDocComment: "the first parameter!\nparam on expression\nOn parameter ", + docComment: "Summary on expression\nOn variable", + parameterDocComment: "On parameter \nparam on expression\nthe first parameter!", tags: [ - { name: "param", text: "s the first parameter!" }, - { name: "returns", text: "the parameter's length" }, { name: "param", text: "s param on expression" }, { name: "returns", text: "return on expression" }, + { name: "param", text: "s the first parameter!" }, + { name: "returns", text: "the parameter's length" }, ], }); From 48e1a891a6343cea94a27a845fad04a13ee00eb9 Mon Sep 17 00:00:00 2001 From: dangoo Date: Tue, 19 Jun 2018 21:28:49 +0200 Subject: [PATCH 08/27] Add Intl.NumberFormat.formatToParts types --- src/lib/esnext.d.ts | 1 + src/lib/esnext.intl.d.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/lib/esnext.intl.d.ts diff --git a/src/lib/esnext.d.ts b/src/lib/esnext.d.ts index 99e71158f6a..970e1b32b3e 100644 --- a/src/lib/esnext.d.ts +++ b/src/lib/esnext.d.ts @@ -2,3 +2,4 @@ /// /// /// +/// diff --git a/src/lib/esnext.intl.d.ts b/src/lib/esnext.intl.d.ts new file mode 100644 index 00000000000..99e202bd91b --- /dev/null +++ b/src/lib/esnext.intl.d.ts @@ -0,0 +1,12 @@ +declare namespace Intl { + type NumberFormatPartTypes = "currency" | "decimal" | "fraction" | "group" | "infinity" | "integer" | "literal" | "minusSign" | "nan" | "plusSign" | "percentSign"; + + interface NumberFormatPart { + type: NumberFormatPartTypes; + value: string; + } + + interface NumberFormat { + formatToParts(number?: number): NumberFormatPart[]; + } + } From b7f5f2a92b8f8c90956ea7fb5120dfc906f4cfce Mon Sep 17 00:00:00 2001 From: dangoo Date: Tue, 19 Jun 2018 22:24:32 +0200 Subject: [PATCH 09/27] Add missing references in clparser and libs.json --- src/compiler/commandLineParser.ts | 1 + src/lib/libs.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index f8648636c8a..98cbaca5e6f 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -44,6 +44,7 @@ namespace ts { ["esnext.array", "lib.esnext.array.d.ts"], ["esnext.symbol", "lib.esnext.symbol.d.ts"], ["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"], + ["esnext.intl", "lib.esnext.intl.d.ts"] ]; /** diff --git a/src/lib/libs.json b/src/lib/libs.json index 07c99278c14..1f2079e33a3 100644 --- a/src/lib/libs.json +++ b/src/lib/libs.json @@ -35,6 +35,7 @@ "esnext.asynciterable", "esnext.array", "esnext.symbol", + "esnext.intl", // Default libraries "es5.full", "es2015.full", @@ -50,4 +51,4 @@ "es5.full": "lib.d.ts", "es2015.full": "lib.es6.d.ts" } -} \ No newline at end of file +} From db85f3766964c4abb57b5f02d59c492e82477305 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 19 Jun 2018 13:44:00 -0700 Subject: [PATCH 10/27] fixUnusedIdentifier: Don't needlessly exclude jsdoc (#25014) --- src/services/codefixes/fixUnusedIdentifier.ts | 4 ++-- .../fixUnusedIdentifier_jsdocTypeParameter.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/fixUnusedIdentifier_jsdocTypeParameter.ts diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index ad3e2e36f5b..505a09813c3 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -173,8 +173,8 @@ namespace ts.codefix { const typeParameters = getEffectiveTypeParameterDeclarations(parent.parent); if (typeParameters.length === 1) { const { pos, end } = cast(typeParameters, isNodeArray); - const previousToken = getTokenAtPosition(sourceFile, pos - 1, /*includeJsDocComment*/ false); - const nextToken = getTokenAtPosition(sourceFile, end, /*includeJsDocComment*/ false); + const previousToken = getTokenAtPosition(sourceFile, pos - 1, /*includeJsDocComment*/ true); + const nextToken = getTokenAtPosition(sourceFile, end, /*includeJsDocComment*/ true); Debug.assert(previousToken.kind === SyntaxKind.LessThanToken); Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken); diff --git a/tests/cases/fourslash/fixUnusedIdentifier_jsdocTypeParameter.ts b/tests/cases/fourslash/fixUnusedIdentifier_jsdocTypeParameter.ts new file mode 100644 index 00000000000..efa096e81a1 --- /dev/null +++ b/tests/cases/fourslash/fixUnusedIdentifier_jsdocTypeParameter.ts @@ -0,0 +1,18 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +/////** +//// * @type {() => void} +//// */ +////export const x = 0; + +verify.codeFix({ + description: "Remove declaration for: 'T'", + newFileContent: +`/** + * @type {() => void} + */ +export const x = 0;`, +}); From 7f553f4f932ee91d17d22cdfe7aaf1494218299f Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 19 Jun 2018 13:46:03 -0700 Subject: [PATCH 11/27] refactorConvertToGetAccessAndSetAccess: Don't trigger on leading trivia (#25054) * refactorConvertToGetAccessAndSetAccess: Don't trigger on leading trivia * Update API (#24966) --- src/harness/fourslash.ts | 10 ++++++- .../generateGetAccessorAndSetAccessor.ts | 29 +++++++++---------- src/services/utilities.ts | 4 +++ .../reference/api/tsserverlibrary.d.ts | 1 + tests/cases/fourslash/fourslash.ts | 1 + ...ToGetAccessAndSetAccess_notOnWhitespace.ts | 8 +++++ 6 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess_notOnWhitespace.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0ca37715b9f..177d98c37ba 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -3045,6 +3045,10 @@ Actual: ${stringify(fullActual)}`); } } + public verifyRefactorsAvailable(names: ReadonlyArray): void { + assert.deepEqual(unique(this.getApplicableRefactors(this.getSelection()), r => r.name), names); + } + public verifyRefactor({ name, actionName, refactors }: FourSlashInterface.VerifyRefactorOptions) { const actualRefactors = this.getApplicableRefactors(this.getSelection()).filter(r => r.name === name && r.actions.some(a => a.name === actionName)); this.assertObjectsEqual(actualRefactors, refactors); @@ -3815,7 +3819,7 @@ ${code} } /** Collects an array of unique outputs. */ - function unique(inputs: T[], getOutput: (t: T) => string): string[] { + function unique(inputs: ReadonlyArray, getOutput: (t: T) => string): string[] { const set = ts.createMap(); for (const input of inputs) { const out = getOutput(input); @@ -4106,6 +4110,10 @@ namespace FourSlashInterface { this.state.verifyApplicableRefactorAvailableForRange(this.negative); } + public refactorsAvailable(names: ReadonlyArray): void { + this.state.verifyRefactorsAvailable(names); + } + public refactor(options: VerifyRefactorOptions) { this.state.verifyRefactor(options); } diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index 2e4f11c4b27..b7240f2e985 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -9,20 +9,19 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { type ContainerDeclaration = ClassLikeDeclaration | ObjectLiteralExpression; interface Info { - container: ContainerDeclaration; - isStatic: boolean; - isReadonly: boolean; - type: TypeNode | undefined; - declaration: AcceptedDeclaration; - fieldName: AcceptedNameType; - accessorName: AcceptedNameType; - originalName: AcceptedNameType; - renameAccessor: boolean; + readonly container: ContainerDeclaration; + readonly isStatic: boolean; + readonly isReadonly: boolean; + readonly type: TypeNode | undefined; + readonly declaration: AcceptedDeclaration; + readonly fieldName: AcceptedNameType; + readonly accessorName: AcceptedNameType; + readonly originalName: AcceptedNameType; + readonly renameAccessor: boolean; } function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { - const { file } = context; - if (!getConvertibleFieldAtPosition(context, file)) return undefined; + if (!getConvertibleFieldAtPosition(context)) return undefined; return [{ name: actionName, @@ -39,7 +38,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { function getEditsForAction(context: RefactorContext, _actionName: string): RefactorEditInfo | undefined { const { file } = context; - const fieldInfo = getConvertibleFieldAtPosition(context, file); + const fieldInfo = getConvertibleFieldAtPosition(context); if (!fieldInfo) return undefined; const isJS = isSourceFileJavaScript(file); @@ -117,14 +116,14 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { return name.charCodeAt(0) === CharacterCodes._; } - function getConvertibleFieldAtPosition(context: RefactorContext, file: SourceFile): Info | undefined { - const { startPosition, endPosition } = context; + function getConvertibleFieldAtPosition(context: RefactorContext): Info | undefined { + const { file, startPosition, endPosition } = context; const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); const declaration = findAncestor(node.parent, isAcceptedDeclaration); // make sure declaration have AccessibilityModifier or Static Modifier or Readonly Modifier const meaning = ModifierFlags.AccessibilityModifier | ModifierFlags.Static | ModifierFlags.Readonly; - if (!declaration || !rangeOverlapsWithStartEnd(declaration.name, startPosition, endPosition!) // TODO: GH#18217 + if (!declaration || !nodeOverlapsWithStartEnd(declaration.name, file, startPosition, endPosition!) // TODO: GH#18217 || !isConvertibleName(declaration.name) || (getModifierFlags(declaration) | meaning) !== meaning) return undefined; const name = declaration.name.text; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 9715d124d7e..e3f4f6523fb 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -439,6 +439,10 @@ namespace ts { return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end); } + export function nodeOverlapsWithStartEnd(node: Node, sourceFile: SourceFile, start: number, end: number) { + return startEndOverlapsWithStartEnd(node.getStart(sourceFile), node.end, start, end); + } + export function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number) { const start = Math.max(start1, start2); const end = Math.min(end1, end2); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index eaac2305bc7..74045ba417d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10670,6 +10670,7 @@ declare namespace ts { function startEndContainsRange(start: number, end: number, range: TextRange): boolean; function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean; function rangeOverlapsWithStartEnd(r1: TextRange, start: number, end: number): boolean; + function nodeOverlapsWithStartEnd(node: Node, sourceFile: SourceFile, start: number, end: number): boolean; function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number): boolean; /** * Assumes `candidate.start <= position` holds. diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index a70d6dcf424..89e1948ce77 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -190,6 +190,7 @@ declare namespace FourSlashInterface { applicableRefactorAvailableForRange(): void; refactorAvailable(name: string, actionName?: string): void; + refactorsAvailable(names: ReadonlyArray): void; refactor(options: { name: string; actionName: string; diff --git a/tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess_notOnWhitespace.ts b/tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess_notOnWhitespace.ts new file mode 100644 index 00000000000..9ba208b8e95 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToGetAccessAndSetAccess_notOnWhitespace.ts @@ -0,0 +1,8 @@ +/// + +////class A { +/////*a*/ /*b*/p = 0; +////} + +goTo.select("a", "b"); +verify.refactorsAvailable([]); From 2ef73ab4fae61044f62945756924066d620ebda0 Mon Sep 17 00:00:00 2001 From: dangoo Date: Tue, 19 Jun 2018 22:58:26 +0200 Subject: [PATCH 12/27] Fix test messages to mention esnext.intl --- src/testRunner/unittests/commandLineParsing.ts | 6 +++--- .../unittests/convertCompilerOptionsFromJson.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/testRunner/unittests/commandLineParsing.ts b/src/testRunner/unittests/commandLineParsing.ts index cf7cabdd26d..7145b9e5ec4 100644 --- a/src/testRunner/unittests/commandLineParsing.ts +++ b/src/testRunner/unittests/commandLineParsing.ts @@ -57,7 +57,7 @@ namespace ts { assertParseResult(["--lib", "es5,invalidOption", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, @@ -259,7 +259,7 @@ namespace ts { assertParseResult(["--lib", "es5,", "es7", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, @@ -278,7 +278,7 @@ namespace ts { assertParseResult(["--lib", "es5, ", "es7", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, diff --git a/src/testRunner/unittests/convertCompilerOptionsFromJson.ts b/src/testRunner/unittests/convertCompilerOptionsFromJson.ts index b1695ad01f5..3b422e9a645 100644 --- a/src/testRunner/unittests/convertCompilerOptionsFromJson.ts +++ b/src/testRunner/unittests/convertCompilerOptionsFromJson.ts @@ -263,7 +263,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -294,7 +294,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -325,7 +325,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -356,7 +356,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] From b3f9ec3796285d1d0e0eb1490b164900c576fcf4 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 19 Jun 2018 16:36:18 -0700 Subject: [PATCH 13/27] Fix bug: Still implement a method even if the return type is defined in another file (#24978) --- src/compiler/checker.ts | 9 +++---- src/compiler/types.ts | 1 + ...ClassImplementInterface_typeInOtherFile.ts | 25 +++++++++++++++++++ ...nferFromUsageSetterWithInaccessibleType.ts | 11 +++++++- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/codeFixClassImplementInterface_typeInOtherFile.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1ecf30690a0..ff1da5db911 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4110,15 +4110,14 @@ namespace ts { if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { return declarationNameToString((declaration.parent).name); } - if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { - context.encounteredError = true; - } switch (declaration.kind) { case SyntaxKind.ClassExpression: - return "(Anonymous class)"; case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return "(Anonymous function)"; + if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { + context.encounteredError = true; + } + return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" : "(Anonymous function)"; } } const nameType = symbol.nameType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9e520241fae..b1e52d68bc0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3066,6 +3066,7 @@ namespace ts { Subtype } + // NOTE: If modifying this enum, must modify `TypeFormatFlags` too! export const enum NodeBuilderFlags { None = 0, // Options diff --git a/tests/cases/fourslash/codeFixClassImplementInterface_typeInOtherFile.ts b/tests/cases/fourslash/codeFixClassImplementInterface_typeInOtherFile.ts new file mode 100644 index 00000000000..712bf48e059 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementInterface_typeInOtherFile.ts @@ -0,0 +1,25 @@ +/// + +// @Filename: /I.ts +////export interface J {} +////export interface I { +//// x: J; +//// m(): J; +////} + +// @Filename: /C.ts +////import { I } from "./I"; +////export class C implements I {} + +goTo.file("/C.ts"); +verify.codeFix({ + description: "Implement interface 'I'", + newFileContent: +`import { I } from "./I"; +export class C implements I { + x: import("/I").J; + m(): import("/I").J { + throw new Error("Method not implemented."); + } +}`, +}); diff --git a/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts b/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts index 9e56fc70734..b56c6e05f69 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts @@ -13,4 +13,13 @@ ////} goTo.file("/b.ts"); -verify.not.codeFixAvailable(); +verify.codeFix({ + index: 0, + description: "Infer type of 'x' from usage", + newFileContent: +`export class C { + set x(val: Promise) { val; } + method() { this.x = import("./a"); } +}`, +}); + From 28e0fc56bb536453892c3ed70d77c3dbe89b292f Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Wed, 20 Jun 2018 07:15:36 -0700 Subject: [PATCH 14/27] Update user baselines (#25091) --- tests/baselines/reference/user/uglify-js.log | 172 +++++++++---------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/tests/baselines/reference/user/uglify-js.log b/tests/baselines/reference/user/uglify-js.log index 4fb7b01a2c9..f37d91c289a 100644 --- a/tests/baselines/reference/user/uglify-js.log +++ b/tests/baselines/reference/user/uglify-js.log @@ -1,95 +1,95 @@ Exit Code: 1 Standard output: -node_modules/uglify-js/lib/ast.js(210,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/ast.js(332,33): error TS2339: Property 'transform' does not exist on type 'string'. -node_modules/uglify-js/lib/ast.js(877,5): error TS2322: Type '{ [x: string]: any; _visit: (node: any, descend: any) => any; parent: (n: any) => any; push: type...' is not assignable to type 'TreeWalker'. +node_modules/uglify-js/lib/ast.js(209,23): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/ast.js(331,33): error TS2339: Property 'transform' does not exist on type 'string'. +node_modules/uglify-js/lib/ast.js(872,5): error TS2322: Type '{ [x: string]: any; _visit: (node: any, descend: any) => any; parent: (n: any) => any; push: type...' is not assignable to type 'TreeWalker'. Object literal may only specify known properties, but '_visit' does not exist in type 'TreeWalker'. Did you mean to write 'visit'? node_modules/uglify-js/lib/compress.js(165,27): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(514,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(829,18): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1084,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(1098,51): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'true | ((node: any) => any)' has no compatible call signatures. -node_modules/uglify-js/lib/compress.js(1162,53): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(1204,112): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(1205,29): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(1214,87): error TS2322: Type 'false' is not assignable to type 'number'. -node_modules/uglify-js/lib/compress.js(1222,29): error TS2322: Type 'false' is not assignable to type 'never'. -node_modules/uglify-js/lib/compress.js(1325,38): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1417,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(1514,27): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1546,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1960,44): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(2152,19): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(2412,27): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3152,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3165,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. -node_modules/uglify-js/lib/compress.js(3302,18): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3312,33): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3316,32): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3322,40): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3331,41): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3348,14): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3350,40): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3358,33): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3432,63): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3621,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3638,36): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3644,38): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3648,40): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3673,22): error TS2339: Property 'each' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3678,30): error TS2339: Property 'del' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3683,30): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3694,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3696,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3708,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3710,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3816,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(3818,36): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3847,22): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3867,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. -node_modules/uglify-js/lib/compress.js(3892,30): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4030,18): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4329,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(4413,22): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4761,30): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4768,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ [x: string]: any; get: () => string; toString: () => string; indent: () => void; indentation: (...'. -node_modules/uglify-js/lib/compress.js(4772,36): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(4777,41): error TS2339: Property 'get' does not exist on type 'string'. -node_modules/uglify-js/lib/compress.js(5264,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. -node_modules/uglify-js/lib/compress.js(5703,25): error TS2365: Operator '==' cannot be applied to types 'boolean' and '"f"'. -node_modules/uglify-js/lib/compress.js(5730,32): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5790,24): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5862,24): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5868,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(6218,43): error TS2454: Variable 'property' is used before being assigned. -node_modules/uglify-js/lib/compress.js(6232,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6235,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. -node_modules/uglify-js/lib/compress.js(6242,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6295,19): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(501,26): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(816,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1071,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1085,51): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'true | ((node: any) => any)' has no compatible call signatures. +node_modules/uglify-js/lib/compress.js(1149,53): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1191,112): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(1192,29): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(1201,87): error TS2322: Type 'false' is not assignable to type 'number'. +node_modules/uglify-js/lib/compress.js(1209,29): error TS2322: Type 'false' is not assignable to type 'never'. +node_modules/uglify-js/lib/compress.js(1312,38): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1407,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1503,27): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1535,26): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1949,44): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(2141,19): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(2401,27): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3141,23): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3154,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. +node_modules/uglify-js/lib/compress.js(3291,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3301,33): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3305,32): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3311,40): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3320,41): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3337,14): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3339,40): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3347,33): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3421,63): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3608,23): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3629,24): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3635,26): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3639,28): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3657,18): error TS2339: Property 'each' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3662,26): error TS2339: Property 'del' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3667,26): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3678,37): error TS2339: Property 'has' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3680,44): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3692,37): error TS2339: Property 'has' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3694,44): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3798,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(3800,36): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3830,22): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3850,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. +node_modules/uglify-js/lib/compress.js(3875,30): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4013,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4312,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(4396,22): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4746,30): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4753,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ [x: string]: any; get: () => string; toString: () => string; indent: () => void; indentation: (...'. +node_modules/uglify-js/lib/compress.js(4757,36): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(4762,41): error TS2339: Property 'get' does not exist on type 'string'. +node_modules/uglify-js/lib/compress.js(5249,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. +node_modules/uglify-js/lib/compress.js(5688,25): error TS2365: Operator '==' cannot be applied to types 'boolean' and '"f"'. +node_modules/uglify-js/lib/compress.js(5715,32): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5775,24): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5847,24): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5853,26): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6213,43): error TS2454: Variable 'property' is used before being assigned. +node_modules/uglify-js/lib/compress.js(6228,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6231,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. +node_modules/uglify-js/lib/compress.js(6237,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6290,19): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/minify.js(170,75): error TS2339: Property 'compress' does not exist on type 'Compressor'. -node_modules/uglify-js/lib/mozilla-ast.js(569,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/mozilla-ast.js(566,18): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/output.js(481,22): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/output.js(774,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/output.js(1186,29): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/output.js(1480,58): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. -node_modules/uglify-js/lib/parse.js(365,20): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. +node_modules/uglify-js/lib/output.js(1170,29): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/output.js(1452,58): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +node_modules/uglify-js/lib/parse.js(367,20): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'. -node_modules/uglify-js/lib/parse.js(447,32): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. -node_modules/uglify-js/lib/parse.js(458,32): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. -node_modules/uglify-js/lib/parse.js(509,20): error TS2339: Property 'raw_source' does not exist on type 'RegExp'. -node_modules/uglify-js/lib/parse.js(620,57): error TS2339: Property 'push' does not exist on type 'never'. -node_modules/uglify-js/lib/parse.js(630,32): error TS2345: Argument of type 'never[]' is not assignable to parameter of type 'never'. -node_modules/uglify-js/lib/parse.js(636,40): error TS2339: Property 'length' does not exist on type 'never'. -node_modules/uglify-js/lib/parse.js(740,13): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(772,52): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(772,74): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(814,31): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(820,17): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(824,21): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(829,43): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(848,21): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(867,21): error TS2531: Object is possibly 'null'. -node_modules/uglify-js/lib/parse.js(982,23): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +node_modules/uglify-js/lib/parse.js(449,32): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +node_modules/uglify-js/lib/parse.js(460,32): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +node_modules/uglify-js/lib/parse.js(511,20): error TS2339: Property 'raw_source' does not exist on type 'RegExp'. +node_modules/uglify-js/lib/parse.js(622,57): error TS2339: Property 'push' does not exist on type 'never'. +node_modules/uglify-js/lib/parse.js(632,32): error TS2345: Argument of type 'never[]' is not assignable to parameter of type 'never'. +node_modules/uglify-js/lib/parse.js(638,40): error TS2339: Property 'length' does not exist on type 'never'. +node_modules/uglify-js/lib/parse.js(739,13): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(771,52): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(771,74): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(815,31): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(821,17): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(825,21): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(830,43): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(849,21): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(868,21): error TS2531: Object is possibly 'null'. +node_modules/uglify-js/lib/parse.js(983,23): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. node_modules/uglify-js/lib/parse.js(1097,9): error TS2322: Type 'any[]' is not assignable to type 'never[]'. Type 'any' is not assignable to type 'never'. node_modules/uglify-js/lib/parse.js(1156,17): error TS2531: Object is possibly 'null'. @@ -111,8 +111,8 @@ node_modules/uglify-js/lib/scope.js(202,19): error TS2554: Expected 0 arguments, node_modules/uglify-js/lib/scope.js(410,14): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/scope.js(465,15): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/scope.js(490,15): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/sourcemap.js(56,25): error TS2304: Cannot find name 'MOZ_SourceMap'. -node_modules/uglify-js/lib/sourcemap.js(62,23): error TS2304: Cannot find name 'MOZ_SourceMap'. +node_modules/uglify-js/lib/sourcemap.js(55,25): error TS2304: Cannot find name 'MOZ_SourceMap'. +node_modules/uglify-js/lib/sourcemap.js(61,23): error TS2304: Cannot find name 'MOZ_SourceMap'. node_modules/uglify-js/tools/exit.js(7,32): error TS2339: Property 'bufferSize' does not exist on type 'WriteStream'. node_modules/uglify-js/tools/exit.js(7,61): error TS2339: Property 'bufferSize' does not exist on type 'WriteStream'. node_modules/uglify-js/tools/node.js(68,27): error TS2339: Property 'minify' does not exist on type 'typeof import("/uglify-js/node_modules/uglify-js/tools/node")'. From 1c3259d29b9244ce43b1b4e7e45e37a614b29d7c Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 20 Jun 2018 09:13:04 -0700 Subject: [PATCH 15/27] Add CompletionInfo command to protocol (#25080) * Add CompletionInfo command to protocol * Add comments to protocol --- src/server/protocol.ts | 14 ++++++ src/server/session.ts | 44 ++++++++++++------- .../reference/api/tsserverlibrary.d.ts | 10 +++++ 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 2f128aa1663..49fb54a6b10 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -14,7 +14,9 @@ namespace ts.server.protocol { GetSpanOfEnclosingComment = "getSpanOfEnclosingComment", Change = "change", Close = "close", + /** @deprecated Prefer CompletionInfo -- see comment on CompletionsResponse */ Completions = "completions", + CompletionInfo = "completionInfo", /* @internal */ CompletionsFull = "completions-full", CompletionDetails = "completionEntryDetails", @@ -1943,10 +1945,22 @@ namespace ts.server.protocol { source?: SymbolDisplayPart[]; } + /** @deprecated Prefer CompletionInfoResponse, which supports several top-level fields in addition to the array of entries. */ export interface CompletionsResponse extends Response { body?: CompletionEntry[]; } + export interface CompletionInfoResponse extends Response { + body?: CompletionInfo; + } + + export interface CompletionInfo { + readonly isGlobalCompletion: boolean; + readonly isMemberCompletion: boolean; + readonly isNewIdentifierLocation: boolean; + readonly entries: ReadonlyArray; + } + export interface CompletionDetailsResponse extends Response { body?: CompletionEntryDetails[]; } diff --git a/src/server/session.ts b/src/server/session.ts index 74629d97e48..c6934bb8d82 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1343,8 +1343,7 @@ namespace ts.server { }); } - private getCompletions(args: protocol.CompletionsRequestArgs, simplifiedResult: boolean): ReadonlyArray | CompletionInfo | undefined { - const prefix = args.prefix || ""; + private getCompletions(args: protocol.CompletionsRequestArgs, kind: protocol.CommandTypes.CompletionInfo | protocol.CommandTypes.Completions | protocol.CommandTypes.CompletionsFull): ReadonlyArray | protocol.CompletionInfo | CompletionInfo | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -1355,19 +1354,27 @@ namespace ts.server { includeExternalModuleExports: args.includeExternalModuleExports, includeInsertTextCompletions: args.includeInsertTextCompletions }); - if (simplifiedResult) { - return mapDefined(completions && completions.entries, entry => { - if (completions!.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) { - const { name, kind, kindModifiers, sortText, insertText, replacementSpan, hasAction, source, isRecommended } = entry; - const convertedSpan = replacementSpan ? this.toLocationTextSpan(replacementSpan, scriptInfo) : undefined; - // Use `hasAction || undefined` to avoid serializing `false`. - return { name, kind, kindModifiers, sortText, insertText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source, isRecommended }; - } - }).sort((a, b) => compareStringsCaseSensitiveUI(a.name, b.name)); - } - else { - return completions; - } + if (completions === undefined) return undefined; + + if (kind === protocol.CommandTypes.CompletionsFull) return completions; + + const prefix = args.prefix || ""; + const entries = mapDefined(completions.entries, entry => { + if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) { + const { name, kind, kindModifiers, sortText, insertText, replacementSpan, hasAction, source, isRecommended } = entry; + const convertedSpan = replacementSpan ? this.toLocationTextSpan(replacementSpan, scriptInfo) : undefined; + // Use `hasAction || undefined` to avoid serializing `false`. + return { name, kind, kindModifiers, sortText, insertText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source, isRecommended }; + } + }).sort((a, b) => compareStringsCaseSensitiveUI(a.name, b.name)); + + if (kind === protocol.CommandTypes.Completions) return entries; + + const res: protocol.CompletionInfo = { + ...completions, + entries, + }; + return res; } private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs, simplifiedResult: boolean): ReadonlyArray | ReadonlyArray { @@ -2035,11 +2042,14 @@ namespace ts.server { [CommandNames.FormatRangeFull]: (request: protocol.FormatRequest) => { return this.requiredResponse(this.getFormattingEditsForRangeFull(request.arguments)); }, + [CommandNames.CompletionInfo]: (request: protocol.CompletionsRequest) => { + return this.requiredResponse(this.getCompletions(request.arguments, CommandNames.CompletionInfo)); + }, [CommandNames.Completions]: (request: protocol.CompletionsRequest) => { - return this.requiredResponse(this.getCompletions(request.arguments, /*simplifiedResult*/ true)); + return this.requiredResponse(this.getCompletions(request.arguments, CommandNames.Completions)); }, [CommandNames.CompletionsFull]: (request: protocol.CompletionsRequest) => { - return this.requiredResponse(this.getCompletions(request.arguments, /*simplifiedResult*/ false)); + return this.requiredResponse(this.getCompletions(request.arguments, CommandNames.CompletionsFull)); }, [CommandNames.CompletionDetails]: (request: protocol.CompletionDetailsRequest) => { return this.requiredResponse(this.getCompletionEntryDetails(request.arguments, /*simplifiedResult*/ true)); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 74045ba417d..114b2341fa9 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -12175,6 +12175,7 @@ declare namespace ts.server.protocol { Change = "change", Close = "close", Completions = "completions", + CompletionInfo = "completionInfo", CompletionsFull = "completions-full", CompletionDetails = "completionEntryDetails", CompletionDetailsFull = "completionEntryDetails-full", @@ -12876,6 +12877,15 @@ declare namespace ts.server.protocol { interface CompletionsResponse extends Response { body?: CompletionEntry[]; } + interface CompletionInfoResponse extends Response { + body?: CompletionInfo; + } + interface CompletionInfo { + readonly isGlobalCompletion: boolean; + readonly isMemberCompletion: boolean; + readonly isNewIdentifierLocation: boolean; + readonly entries: ReadonlyArray; + } interface CompletionDetailsResponse extends Response { body?: CompletionEntryDetails[]; } From f506b28e95edc88d18e0fe1c3343e2a7f6a49971 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 20 Jun 2018 12:25:51 -0700 Subject: [PATCH 16/27] Mark the declarations visible correctly when emit is disabled but asked to emit declarations for watch mode Fixes #25068 --- src/compiler/emitter.ts | 19 +++++++ src/compiler/types.ts | 2 +- src/harness/virtualFileSystemWithWatch.ts | 4 +- src/testRunner/unittests/tscWatchMode.ts | 52 +++++++++++++++++++ .../reference/api/tsserverlibrary.d.ts | 2 +- 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7269462578e..1857fa05f60 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -192,6 +192,11 @@ namespace ts { // Setup and perform the transformation to retrieve declarations from the input files const nonJsFiles = filter(sourceFiles, isSourceFileNotJavaScript); const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles; + if (emitOnlyDtsFiles && !compilerOptions.declaration) { + // Checker wont collect the linked aliases since thats only done when declaration is enabled. + // Do that here when emitting only dts files + nonJsFiles.forEach(collectLinkedAliases); + } const declarationTransform = transformNodes(resolver, host, compilerOptions, inputListOrBundle, concatenate([transformDeclarations], declarationTransformers), /*allowDtsFiles*/ false); if (length(declarationTransform.diagnostics)) { for (const diagnostic of declarationTransform.diagnostics!) { @@ -221,6 +226,20 @@ namespace ts { declarationTransform.dispose(); } + function collectLinkedAliases(node: Node) { + if (isExportAssignment(node)) { + if (node.expression.kind === SyntaxKind.Identifier) { + resolver.collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); + } + return; + } + else if (isExportSpecifier(node)) { + resolver.collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); + return; + } + forEachChild(node, collectLinkedAliases); + } + function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, sourceFileOrBundle: SourceFile | Bundle, bundleInfoPath: string | undefined, printer: Printer, mapRecorder: SourceMapWriter) { const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined; const sourceFile = sourceFileOrBundle.kind === SyntaxKind.SourceFile ? sourceFileOrBundle : undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b1e52d68bc0..65856ca23f9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3331,7 +3331,7 @@ namespace ts { getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; isLateBound(node: Declaration): node is LateBoundDeclaration; - collectLinkedAliases(node: Identifier): Node[] | undefined; + collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined; isImplementationOfOverload(node: FunctionLike): boolean | undefined; isRequiredInitializedParameter(node: ParameterDeclaration): boolean; isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 467a3474100..6645e12c832 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -571,7 +571,9 @@ interface Array {}` } private addFileOrFolderInFolder(folder: FsFolder, fileOrDirectory: FsFile | FsFolder | FsSymLink, ignoreWatch?: boolean) { - insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path))); + if (!this.fs.has(fileOrDirectory.path)) { + insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path))); + } folder.modifiedTime = this.now(); this.fs.set(fileOrDirectory.path, fileOrDirectory); diff --git a/src/testRunner/unittests/tscWatchMode.ts b/src/testRunner/unittests/tscWatchMode.ts index 2aaef43f2d9..ed03c6ad48d 100644 --- a/src/testRunner/unittests/tscWatchMode.ts +++ b/src/testRunner/unittests/tscWatchMode.ts @@ -1218,6 +1218,58 @@ namespace ts.tscWatch { checkWatchedFiles(host, files.map(f => f.path)); } }); + + it("updates errors correctly when declaration emit is disabled in compiler options", () => { + const currentDirectory = "/user/username/projects/myproject"; + const aFile: File = { + path: `${currentDirectory}/a.ts`, + content: `import test from './b'; +test(4, 5);` + }; + const bFileContent = `function test(x: number, y: number) { + return x + y / 5; +} +export default test;`; + const bFile: File = { + path: `${currentDirectory}/b.ts`, + content: bFileContent + }; + const tsconfigFile: File = { + path: `${currentDirectory}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + module: "commonjs", + noEmit: true, + strict: true, + } + }) + }; + const files = [aFile, bFile, libFile, tsconfigFile]; + const host = createWatchedSystem(files, { currentDirectory }); + const watch = createWatchOfConfigFile("tsconfig.json", host); + checkOutputErrorsInitial(host, emptyArray); + + changeParameterType("x", "string", [ + getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.indexOf("4"), 1, Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1, "4", "string") + ]); + changeParameterType("y", "string", [ + getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.indexOf("5"), 1, Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1, "5", "string"), + getDiagnosticOfFileFromProgram(watch(), bFile.path, bFile.content.indexOf("y /"), 1, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type) + ]); + + function changeParameterType(parameterName: string, toType: string, expectedErrors: ReadonlyArray) { + const newContent = bFileContent.replace(new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`); + + verifyErrorsWithBFileContents(newContent, expectedErrors); + verifyErrorsWithBFileContents(bFileContent, emptyArray); + } + + function verifyErrorsWithBFileContents(content: string, expectedErrors: ReadonlyArray) { + host.writeFile(bFile.path, content); + host.runQueuedTimeoutCallbacks(); + checkOutputErrorsIncremental(host, expectedErrors); + } + }); }); describe("tsc-watch emit with outFile or out setting", () => { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 114b2341fa9..097a8caec57 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2915,7 +2915,7 @@ declare namespace ts { getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; isLateBound(node: Declaration): node is LateBoundDeclaration; - collectLinkedAliases(node: Identifier): Node[] | undefined; + collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined; isImplementationOfOverload(node: FunctionLike): boolean | undefined; isRequiredInitializedParameter(node: ParameterDeclaration): boolean; isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; From f3e2e891da9a50cafd1f10b64872c7d919c223ee Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 20 Jun 2018 12:57:34 -0700 Subject: [PATCH 17/27] navigationBar: Avoid double recursion on special property assignment (#25077) --- src/services/navigationBar.ts | 2 +- .../fourslash/navbarNestedCommonJsExports.ts | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/navbarNestedCommonJsExports.ts diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index f381be9b7d1..d97004b80c5 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -277,7 +277,7 @@ namespace ts.NavigationBar { case SpecialPropertyAssignmentKind.PrototypeProperty: case SpecialPropertyAssignmentKind.Prototype: addNodeWithRecursiveChild(node, (node as BinaryExpression).right); - break; + return; case SpecialPropertyAssignmentKind.ThisProperty: case SpecialPropertyAssignmentKind.Property: case SpecialPropertyAssignmentKind.None: diff --git a/tests/cases/fourslash/navbarNestedCommonJsExports.ts b/tests/cases/fourslash/navbarNestedCommonJsExports.ts new file mode 100644 index 00000000000..3c2d4499172 --- /dev/null +++ b/tests/cases/fourslash/navbarNestedCommonJsExports.ts @@ -0,0 +1,35 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +////exports.a = exports.b = exports.c = 0; + +verify.navigationTree({ + text: "", + kind: "script", + childItems: [ + { + text: "a", + kind: "const", + childItems: [ + { + text: "b", + kind: "const", + childItems: [{ text: "c", kind: "const" }], + }, + ], + }, + ], +}); + +verify.navigationBar([ + { + text: "", + kind: "script", + childItems: [ + { text: "a", kind: "const" }, + ], + }, +]); + From 4a078479e4ae54c03058c675a1594f7d867dd8b8 Mon Sep 17 00:00:00 2001 From: nrcoley <8762012+nrcoley@users.noreply.github.com> Date: Wed, 20 Jun 2018 17:08:09 -0400 Subject: [PATCH 18/27] Remove contributor info --- .mailmap | 1 - 1 file changed, 1 deletion(-) diff --git a/.mailmap b/.mailmap index 4f27b3087b8..774aa4174c3 100644 --- a/.mailmap +++ b/.mailmap @@ -139,7 +139,6 @@ Michael Mike Busyrev Mine Starks Mine Starks Mohamed Hegazy -ncoley # Natalie Coley Nathan Shively-Sanders Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Nathan Yee Nima Zahedi From 0f55566cf48bdc5f817f0b888c6b485e42eff870 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 20 Jun 2018 16:28:30 -0700 Subject: [PATCH 19/27] In JS, always check the extends tag of a class before its heritage clause (#25111) * Check extends tag first in getClassExtendsHeritageClauseElement Previously getBaseTypeNodeOfClass checked, but this is only used in a few places. * Fix names and add test * Update API baseline * Move jsdocAugments tests to conformance/jsdoc * Better naming in checkClassLikeDeclaration --- src/compiler/checker.ts | 29 ++++++++----------- src/compiler/transformers/declarations.ts | 2 +- src/compiler/transformers/es2015.ts | 2 +- src/compiler/transformers/ts.ts | 2 +- src/compiler/utilities.ts | 15 ++++++++-- ...sDoesntImplementInheritedAbstractMember.ts | 2 +- .../fixClassIncorrectlyImplementsInterface.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 3 +- tests/baselines/reference/extendsTag1.symbols | 9 ++++++ tests/baselines/reference/extendsTag1.types | 9 ++++++ tests/cases/conformance/jsdoc/extendsTag1.ts | 10 +++++++ .../jsdoc}/jsdocAugmentsMissingType.ts | 0 .../jsdocAugments_errorInExtendsExpression.ts | 0 .../jsdoc}/jsdocAugments_nameMismatch.ts | 0 .../jsdoc}/jsdocAugments_noExtends.ts | 0 .../jsdoc}/jsdocAugments_notAClass.ts | 0 .../jsdoc}/jsdocAugments_qualifiedName.ts | 0 .../jsdoc}/jsdocAugments_withTypeParameter.ts | 0 18 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 tests/baselines/reference/extendsTag1.symbols create mode 100644 tests/baselines/reference/extendsTag1.types create mode 100644 tests/cases/conformance/jsdoc/extendsTag1.ts rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugmentsMissingType.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_errorInExtendsExpression.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_nameMismatch.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_noExtends.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_notAClass.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_qualifiedName.ts (100%) rename tests/cases/{compiler => conformance/jsdoc}/jsdocAugments_withTypeParameter.ts (100%) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ff1da5db911..5805a496dc1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5392,16 +5392,7 @@ namespace ts { } function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments | undefined { - const decl = type.symbol.valueDeclaration; - if (isInJavaScriptFile(decl)) { - // Prefer an @augments tag because it may have type parameters. - const tag = getJSDocAugmentsTag(decl); - if (tag) { - return tag.class; - } - } - - return getClassExtendsHeritageClauseElement(decl); + return getEffectiveBaseTypeNode(type.symbol.valueDeclaration as ClassLikeDeclaration); } function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray | undefined, location: Node): Signature[] { @@ -5428,7 +5419,7 @@ namespace ts { function getBaseConstructorTypeOfClass(type: InterfaceType): Type { if (!type.resolvedBaseConstructorType) { const decl = type.symbol.valueDeclaration; - const extended = getClassExtendsHeritageClauseElement(decl); + const extended = getEffectiveBaseTypeNode(decl); const baseTypeNode = getBaseTypeNodeOfClass(type); if (!baseTypeNode) { return type.resolvedBaseConstructorType = undefinedType; @@ -14764,7 +14755,7 @@ namespace ts { function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) { const containingClassDecl = container.parent; - const baseTypeNode = getClassExtendsHeritageClauseElement(containingClassDecl); + const baseTypeNode = getEffectiveBaseTypeNode(containingClassDecl); // If a containing class does not have extends clause or the class extends null // skip checking whether super statement is called before "this" accessing. @@ -15040,7 +15031,7 @@ namespace ts { // at this point the only legal case for parent is ClassLikeDeclaration const classLikeDeclaration = container.parent; - if (!getClassExtendsHeritageClauseElement(classLikeDeclaration)) { + if (!getEffectiveBaseTypeNode(classLikeDeclaration)) { error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); return errorType; } @@ -18678,7 +18669,7 @@ namespace ts { if (superType !== errorType) { // In super call, the candidate signatures are the matching arity signatures of the base constructor function instantiated // with the type arguments specified in the extends clause. - const baseTypeNode = getClassExtendsHeritageClauseElement(getContainingClass(node)!); + const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); if (baseTypeNode) { const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); return resolveCall(node, baseConstructors, candidatesOutArray); @@ -21474,7 +21465,7 @@ namespace ts { // Constructors of classes with no extends clause may not contain super calls, whereas // constructors of derived classes must contain at least one super call somewhere in their function body. const containingClassDecl = node.parent; - if (getClassExtendsHeritageClauseElement(containingClassDecl)) { + if (getEffectiveBaseTypeNode(containingClassDecl)) { captureLexicalThis(node.parent, containingClassDecl); const classExtendsNull = classDeclarationExtendsNull(containingClassDecl); const superCall = getSuperCallInConstructor(node); @@ -22651,7 +22642,7 @@ namespace ts { } const name = getIdentifierFromEntityNameExpression(node.class.expression); - const extend = getClassExtendsHeritageClauseElement(classLike); + const extend = getClassExtendsHeritageElement(classLike); if (extend) { const className = getIdentifierFromEntityNameExpression(extend.expression); if (className && name.escapedText !== className.escapedText) { @@ -24426,7 +24417,7 @@ namespace ts { checkClassForStaticPropertyNameConflicts(node); } - const baseTypeNode = getClassExtendsHeritageClauseElement(node); + const baseTypeNode = getEffectiveBaseTypeNode(node); if (baseTypeNode) { if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends); @@ -24439,6 +24430,10 @@ namespace ts { const staticBaseType = getApparentType(baseConstructorType); checkBaseTypeAccessibility(staticBaseType, baseTypeNode); checkSourceElement(baseTypeNode.expression); + const extendsNode = getClassExtendsHeritageElement(node); + if (extendsNode && extendsNode !== baseTypeNode) { + checkExpression(extendsNode.expression); + } if (some(baseTypeNode.typeArguments)) { forEach(baseTypeNode.typeArguments, checkSourceElement); for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) { diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 8e2e3727c60..35fb8e99170 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -1022,7 +1022,7 @@ namespace ts { } const members = createNodeArray(concatenate(parameterProperties, visitNodes(input.members, visitDeclarationSubtree))); - const extendsClause = getClassExtendsHeritageClauseElement(input); + const extendsClause = getEffectiveBaseTypeNode(input); if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) { // We must add a temporary declaration for the extends clause expression diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 8624beae643..8e2b487f13f 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -770,7 +770,7 @@ namespace ts { enableSubstitutionsForBlockScopedBindings(); } - const extendsClauseElement = getClassExtendsHeritageClauseElement(node); + const extendsClauseElement = getEffectiveBaseTypeNode(node); const classFunction = createFunctionExpression( /*modifiers*/ undefined, /*asteriskToken*/ undefined, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6d41e3d36cd..4712be940fe 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -586,7 +586,7 @@ namespace ts { function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray) { let facts = ClassFacts.None; if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties; - const extendsClauseElement = getClassExtendsHeritageClauseElement(node); + const extendsClauseElement = getEffectiveBaseTypeNode(node); if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; if (shouldEmitDecorateCallForClass(node)) facts |= ClassFacts.HasConstructorDecorators; if (childIsDecorated(node)) facts |= ClassFacts.HasMemberDecorators; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index bb5c232687b..7c2a13abbf7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2413,7 +2413,18 @@ namespace ts { return isEntityNameExpression(e) || isClassExpression(e); } - export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) { + export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) { + if (isInJavaScriptFile(node)) { + // Prefer an @augments tag because it may have type parameters. + const tag = getJSDocAugmentsTag(node); + if (tag) { + return tag.class; + } + } + return getClassExtendsHeritageElement(node); + } + + export function getClassExtendsHeritageElement(node: ClassLikeDeclaration | InterfaceDeclaration) { const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword); return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined; } @@ -2426,7 +2437,7 @@ namespace ts { /** Returns the node in an `extends` or `implements` clause of a class or interface. */ export function getAllSuperTypeNodes(node: Node): ReadonlyArray { return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray - : isClassLike(node) ? concatenate(singleElementArray(getClassExtendsHeritageClauseElement(node)), getClassImplementsHeritageClauseElements(node)) || emptyArray + : isClassLike(node) ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getClassImplementsHeritageClauseElements(node)) || emptyArray : emptyArray; } diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts index 95de8857eb2..c0624c5529b 100644 --- a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -33,7 +33,7 @@ namespace ts.codefix { } function addMissingMembers(classDeclaration: ClassLikeDeclaration, sourceFile: SourceFile, checker: TypeChecker, changeTracker: textChanges.ChangeTracker, preferences: UserPreferences): void { - const extendsNode = getClassExtendsHeritageClauseElement(classDeclaration)!; + const extendsNode = getEffectiveBaseTypeNode(classDeclaration)!; const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode)!; // Note that this is ultimately derived from a map indexed by symbol names, diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 781f14566c9..ad093de6327 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -71,7 +71,7 @@ namespace ts.codefix { } function getHeritageClauseSymbolTable (classDeclaration: ClassLikeDeclaration, checker: TypeChecker): SymbolTable { - const heritageClauseNode = getClassExtendsHeritageClauseElement(classDeclaration); + const heritageClauseNode = getEffectiveBaseTypeNode(classDeclaration); if (!heritageClauseNode) return createSymbolTable(); const heritageClauseType = checker.getTypeAtLocation(heritageClauseNode) as InterfaceType; const heritageClauseTypeSymbols = checker.getPropertiesOfType(heritageClauseType); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 097a8caec57..78ad4d58c08 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6293,7 +6293,8 @@ declare namespace ts { function isIdentifierName(node: Identifier): boolean; function isAliasSymbolDeclaration(node: Node): boolean; function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean; - function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration): ExpressionWithTypeArguments | undefined; + function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration): ExpressionWithTypeArguments | undefined; + function getClassExtendsHeritageElement(node: ClassLikeDeclaration | InterfaceDeclaration): ExpressionWithTypeArguments | undefined; function getClassImplementsHeritageClauseElements(node: ClassLikeDeclaration): NodeArray | undefined; /** Returns the node in an `extends` or `implements` clause of a class or interface. */ function getAllSuperTypeNodes(node: Node): ReadonlyArray; diff --git a/tests/baselines/reference/extendsTag1.symbols b/tests/baselines/reference/extendsTag1.symbols new file mode 100644 index 00000000000..f38683338b1 --- /dev/null +++ b/tests/baselines/reference/extendsTag1.symbols @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/bug25101.js === +/** + * @template T + * @extends {Set} Should prefer this Set, not the Set in the heritage clause + */ +class My extends Set {} +>My : Symbol(My, Decl(bug25101.js, 0, 0)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) + diff --git a/tests/baselines/reference/extendsTag1.types b/tests/baselines/reference/extendsTag1.types new file mode 100644 index 00000000000..440861dd47b --- /dev/null +++ b/tests/baselines/reference/extendsTag1.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/bug25101.js === +/** + * @template T + * @extends {Set} Should prefer this Set, not the Set in the heritage clause + */ +class My extends Set {} +>My : My +>Set : Set + diff --git a/tests/cases/conformance/jsdoc/extendsTag1.ts b/tests/cases/conformance/jsdoc/extendsTag1.ts new file mode 100644 index 00000000000..194982760e9 --- /dev/null +++ b/tests/cases/conformance/jsdoc/extendsTag1.ts @@ -0,0 +1,10 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @lib: esnext +// @Filename: bug25101.js +/** + * @template T + * @extends {Set} Should prefer this Set, not the Set in the heritage clause + */ +class My extends Set {} diff --git a/tests/cases/compiler/jsdocAugmentsMissingType.ts b/tests/cases/conformance/jsdoc/jsdocAugmentsMissingType.ts similarity index 100% rename from tests/cases/compiler/jsdocAugmentsMissingType.ts rename to tests/cases/conformance/jsdoc/jsdocAugmentsMissingType.ts diff --git a/tests/cases/compiler/jsdocAugments_errorInExtendsExpression.ts b/tests/cases/conformance/jsdoc/jsdocAugments_errorInExtendsExpression.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_errorInExtendsExpression.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_errorInExtendsExpression.ts diff --git a/tests/cases/compiler/jsdocAugments_nameMismatch.ts b/tests/cases/conformance/jsdoc/jsdocAugments_nameMismatch.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_nameMismatch.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_nameMismatch.ts diff --git a/tests/cases/compiler/jsdocAugments_noExtends.ts b/tests/cases/conformance/jsdoc/jsdocAugments_noExtends.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_noExtends.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_noExtends.ts diff --git a/tests/cases/compiler/jsdocAugments_notAClass.ts b/tests/cases/conformance/jsdoc/jsdocAugments_notAClass.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_notAClass.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_notAClass.ts diff --git a/tests/cases/compiler/jsdocAugments_qualifiedName.ts b/tests/cases/conformance/jsdoc/jsdocAugments_qualifiedName.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_qualifiedName.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_qualifiedName.ts diff --git a/tests/cases/compiler/jsdocAugments_withTypeParameter.ts b/tests/cases/conformance/jsdoc/jsdocAugments_withTypeParameter.ts similarity index 100% rename from tests/cases/compiler/jsdocAugments_withTypeParameter.ts rename to tests/cases/conformance/jsdoc/jsdocAugments_withTypeParameter.ts From 4bb3f645b5ac776a1f167cfe6ef488fef6213bfb Mon Sep 17 00:00:00 2001 From: csigs Date: Thu, 21 Jun 2018 10:10:39 +0000 Subject: [PATCH 20/27] LEGO: check in for master to temporary branch. --- .../diagnosticMessages/diagnosticMessages.generated.json.lcl | 4 ++-- .../diagnosticMessages/diagnosticMessages.generated.json.lcl | 4 ++-- .../diagnosticMessages/diagnosticMessages.generated.json.lcl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index 5f7122bd70c..c735834474e 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -487,7 +487,7 @@ - + @@ -496,7 +496,7 @@ - + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 43e457e6907..e0e6e4a2b1a 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -480,7 +480,7 @@ - + @@ -489,7 +489,7 @@ - + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index 54b82d0468e..d0086211c52 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -480,7 +480,7 @@ - + @@ -489,7 +489,7 @@ - + From 4b7208a79f9e4673af01261c8c022b967abde123 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 21 Jun 2018 13:51:49 +0200 Subject: [PATCH 21/27] Fix the build on case-sensitive file systems. Dashed locale names like `pt-BR` were misspelled as `pt-br` in several locations. This is a follow up fix to #23146. --- Gulpfile.js | 2 +- Jakefile.js | 16 ++++++++-------- scripts/generateLocalizedDiagnosticMessages.ts | 7 +++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Gulpfile.js b/Gulpfile.js index db7bb76d34b..f152db4aafd 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -164,7 +164,7 @@ const generatedLCGFile = path.join(builtLocalDirectory, "enu", "diagnosticMessag * 2. 'src\compiler\diagnosticMessages.generated.json' => 'built\local\ENU\diagnosticMessages.generated.json.lcg' * generate the lcg file (source of messages to localize) from the diagnosticMessages.generated.json */ -const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"] +const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"] .map(f => path.join(builtLocalDirectory, f, "diagnosticMessages.generated.json")) .concat(generatedLCGFile); diff --git a/Jakefile.js b/Jakefile.js index 7a16c681b6e..7eb6852472b 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -21,7 +21,7 @@ else if (process.env.PATH !== undefined) { const host = process.env.TYPESCRIPT_HOST || process.env.host || "node"; -const locales = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]; +const locales = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"]; const defaultTestTimeout = 40000; @@ -172,7 +172,7 @@ task(TaskNames.lkg, [ if (sizeAfter > (sizeBefore * 1.10)) { throw new Error("The lib folder increased by 10% or more. This likely indicates a bug."); } - + complete(); }); }, { async: true }); @@ -341,7 +341,7 @@ file(Paths.servicesDefinitionFile, [TaskNames.coreBuild], function() { }, files }; - + const configFilePath = `built/local/typescriptServices.tsconfig.json`; fs.writeFileSync(configFilePath, JSON.stringify(config, undefined, 2)); tsbuild(configFilePath, false, () => { @@ -683,8 +683,8 @@ function diagnosticsToString(diagnostics, pretty) { /** * Concatenate a list of sourceFiles to a destinationFile - * @param {string} destinationFile - * @param {string[]} sourceFiles + * @param {string} destinationFile + * @param {string[]} sourceFiles * @param {string} extraContent */ function concatenateFiles(destinationFile, sourceFiles, extraContent) { @@ -711,8 +711,8 @@ function appendToFile(path, content) { } /** - * - * @param {string} path + * + * @param {string} path * @returns string */ function readFileSync(path) { @@ -729,7 +729,7 @@ function getDiffTool() { /** * Replaces const enum declarations with non-const enums - * @param {string} text + * @param {string} text */ function removeConstModifierFromEnumDeclarations(text) { return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); diff --git a/scripts/generateLocalizedDiagnosticMessages.ts b/scripts/generateLocalizedDiagnosticMessages.ts index 566eb557fd5..09d117d533b 100644 --- a/scripts/generateLocalizedDiagnosticMessages.ts +++ b/scripts/generateLocalizedDiagnosticMessages.ts @@ -65,11 +65,10 @@ function main(): void { * There are three exceptions, zh-CN, zh-TW and pt-BR. */ function getPreferedLocaleName(localeName: string) { - localeName = localeName.toLowerCase(); switch (localeName) { - case "zh-cn": - case "zh-tw": - case "pt-br": + case "zh-CN": + case "zh-TW": + case "pt-BR": return localeName; default: return localeName.split("-")[0]; From 3e50f502bbdc93411a8b11aee3927d35aba83820 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 21 Jun 2018 09:57:14 -0700 Subject: [PATCH 22/27] Mark some Type[] and Signature[] as ReadonlyArray (#25099) --- src/compiler/checker.ts | 136 +++++++++--------- src/compiler/types.ts | 24 ++-- src/services/services.ts | 4 +- src/services/symbolDisplay.ts | 2 +- src/services/types.ts | 4 +- .../reference/api/tsserverlibrary.d.ts | 20 +-- tests/baselines/reference/api/typescript.d.ts | 14 +- 7 files changed, 103 insertions(+), 101 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5805a496dc1..813dc5c6345 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2589,7 +2589,7 @@ namespace ts { return type; } - function createBooleanType(trueFalseTypes: Type[]): IntrinsicType & UnionType { + function createBooleanType(trueFalseTypes: ReadonlyArray): IntrinsicType & UnionType { const type = getUnionType(trueFalseTypes); type.flags |= TypeFlags.Boolean; type.intrinsicName = "boolean"; @@ -2631,7 +2631,7 @@ namespace ts { return result || emptyArray; } - function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType { + function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: ReadonlyArray, constructSignatures: ReadonlyArray, stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType { (type).members = members; (type).properties = getNamedMembers(members); (type).callSignatures = callSignatures; @@ -2641,7 +2641,7 @@ namespace ts { return type; } - function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType { + function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: ReadonlyArray, constructSignatures: ReadonlyArray, stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType { return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } @@ -3387,7 +3387,7 @@ namespace ts { } function typeReferenceToTypeNode(type: TypeReference) { - const typeArguments: Type[] = type.typeArguments || emptyArray; + const typeArguments: ReadonlyArray = type.typeArguments || emptyArray; if (type.target === globalArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); @@ -3583,7 +3583,7 @@ namespace ts { } } - function mapToTypeNodes(types: Type[] | undefined, context: NodeBuilderContext): TypeNode[] | undefined { + function mapToTypeNodes(types: ReadonlyArray | undefined, context: NodeBuilderContext): TypeNode[] | undefined { if (some(types)) { const result = []; for (const type of types) { @@ -3992,7 +3992,7 @@ namespace ts { } } - function formatUnionTypes(types: Type[]): Type[] { + function formatUnionTypes(types: ReadonlyArray): Type[] { const result: Type[] = []; let flags: TypeFlags = 0; for (let i = 0; i < types.length; i++) { @@ -5395,14 +5395,14 @@ namespace ts { return getEffectiveBaseTypeNode(type.symbol.valueDeclaration as ClassLikeDeclaration); } - function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray | undefined, location: Node): Signature[] { + function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray | undefined, location: Node): ReadonlyArray { const typeArgCount = length(typeArgumentNodes); const isJavaScript = isInJavaScriptFile(location); return filter(getSignaturesOfType(type, SignatureKind.Construct), sig => (isJavaScript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); } - function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray | undefined, location: Node): Signature[] { + function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray | undefined, location: Node): ReadonlyArray { const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJavaScriptFile(location)) : sig); @@ -6152,11 +6152,11 @@ namespace ts { return needApparentType ? getApparentType(type) : type; } - function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) { + function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: ReadonlyArray, typeArguments: ReadonlyArray) { let mapper: TypeMapper; let members: SymbolTable; - let callSignatures: Signature[]; - let constructSignatures: Signature[] | undefined; + let callSignatures: ReadonlyArray; + let constructSignatures: ReadonlyArray | undefined; let stringIndexInfo: IndexInfo | undefined; let numberIndexInfo: IndexInfo | undefined; if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { @@ -6212,9 +6212,9 @@ namespace ts { function createSignature( declaration: SignatureDeclaration | JSDocSignature | undefined, - typeParameters: TypeParameter[] | undefined, + typeParameters: ReadonlyArray | undefined, thisParameter: Symbol | undefined, - parameters: Symbol[], + parameters: ReadonlyArray, resolvedReturnType: Type | undefined, resolvedTypePredicate: TypePredicate | undefined, minArgumentCount: number, @@ -6265,7 +6265,7 @@ namespace ts { return result; } - function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { + function findMatchingSignature(signatureList: ReadonlyArray, signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { for (const s of signatureList) { if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, compareTypesIdentical)) { return s; @@ -6273,7 +6273,7 @@ namespace ts { } } - function findMatchingSignatures(signatureLists: Signature[][], signature: Signature, listIndex: number): Signature[] | undefined { + function findMatchingSignatures(signatureLists: ReadonlyArray>, signature: Signature, listIndex: number): Signature[] | undefined { if (signature.typeParameters) { // We require an exact match for generic signatures, so we only return signatures from the first // signature list and only if they have exact matches in the other signature lists. @@ -6303,7 +6303,7 @@ namespace ts { // Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional // parameters and may differ in return types. When signatures differ in return types, the resulting return // type is the union of the constituent return types. - function getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] { + function getUnionSignatures(types: ReadonlyArray, kind: SignatureKind): Signature[] { const signatureLists = map(types, t => getSignaturesOfType(t, kind)); let result: Signature[] | undefined; for (let i = 0; i < signatureLists.length; i++) { @@ -6333,7 +6333,7 @@ namespace ts { return result || emptyArray; } - function getUnionIndexInfo(types: Type[], kind: IndexKind): IndexInfo | undefined { + function getUnionIndexInfo(types: ReadonlyArray, kind: IndexKind): IndexInfo | undefined { const indexTypes: Type[] = []; let isAnyReadonly = false; for (const type of types) { @@ -6373,7 +6373,7 @@ namespace ts { getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); } - function includeMixinType(type: Type, types: Type[], index: number): Type { + function includeMixinType(type: Type, types: ReadonlyArray, index: number): Type { const mixedTypes: Type[] = []; for (let i = 0; i < types.length; i++) { if (i === index) { @@ -6389,8 +6389,8 @@ namespace ts { function resolveIntersectionTypeMembers(type: IntersectionType) { // The members and properties collections are empty for intersection types. To get all properties of an // intersection type use getPropertiesOfType (only the language service uses this). - let callSignatures: Signature[] = emptyArray; - let constructSignatures: Signature[] = emptyArray; + let callSignatures: ReadonlyArray = emptyArray; + let constructSignatures: ReadonlyArray = emptyArray; let stringIndexInfo: IndexInfo | undefined; let numberIndexInfo: IndexInfo | undefined; const types = type.types; @@ -6728,7 +6728,7 @@ namespace ts { getPropertiesOfObjectType(type); } - function getAllPossiblePropertiesOfTypes(types: Type[]): Symbol[] { + function getAllPossiblePropertiesOfTypes(types: ReadonlyArray): Symbol[] { const unionType = getUnionType(types); if (!(unionType.flags & TypeFlags.Union)) { return getAugmentedPropertiesOfType(unionType); @@ -7132,7 +7132,7 @@ namespace ts { return undefined; } - function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): Signature[] { + function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): ReadonlyArray { if (type.flags & TypeFlags.StructuredType) { const resolved = resolveStructuredTypeMembers(type); return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures; @@ -7144,7 +7144,7 @@ namespace ts { * Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and * maps primitive types and type parameters are to their apparent types. */ - function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] { + function getSignaturesOfType(type: Type, kind: SignatureKind): ReadonlyArray { return getSignaturesOfStructuredType(getApparentType(type), kind); } @@ -7279,7 +7279,7 @@ namespace ts { * Gets the minimum number of type arguments needed to satisfy all non-optional type * parameters. */ - function getMinTypeArgumentCount(typeParameters: TypeParameter[] | undefined): number { + function getMinTypeArgumentCount(typeParameters: ReadonlyArray | undefined): number { let minTypeArgumentCount = 0; if (typeParameters) { for (let i = 0; i < typeParameters.length; i++) { @@ -7299,9 +7299,9 @@ namespace ts { * @param typeParameters The requested type parameters. * @param minTypeArgumentCount The minimum number of required type arguments. */ - function fillMissingTypeArguments(typeArguments: Type[], typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; - function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; - function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { + function fillMissingTypeArguments(typeArguments: Type[], typeParameters: ReadonlyArray | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; + function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: ReadonlyArray | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; + function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: ReadonlyArray | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { const numTypeParameters = length(typeParameters); if (numTypeParameters) { const numTypeArguments = length(typeArguments); @@ -7596,7 +7596,9 @@ namespace ts { } function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature { - typeArguments = fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)!; + return getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + } + function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: ReadonlyArray | undefined): Signature { const instantiations = signature.instantiations || (signature.instantiations = createMap()); const id = getTypeListId(typeArguments); let instantiation = instantiations.get(id); @@ -7606,10 +7608,10 @@ namespace ts { return instantiation; } - function createSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature { + function createSignatureInstantiation(signature: Signature, typeArguments: ReadonlyArray | undefined): Signature { return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); } - function createSignatureTypeMapper(signature: Signature, typeArguments: Type[]): TypeMapper { + function createSignatureTypeMapper(signature: Signature, typeArguments: ReadonlyArray | undefined): TypeMapper { return createTypeMapper(signature.typeParameters!, typeArguments); } @@ -7766,7 +7768,7 @@ namespace ts { return getSymbolOfNode(getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter)!.parent); } - function getTypeListId(types: Type[] | undefined) { + function getTypeListId(types: ReadonlyArray | undefined) { let result = ""; if (types) { const length = types.length; @@ -7794,7 +7796,7 @@ namespace ts { // It is only necessary to do so if a constituent type might be the undefined type, the null type, the type // of an object literal or the anyFunctionType. This is because there are operations in the type checker // that care about the presence of such types at arbitrary depth in a containing type. - function getPropagatingFlagsOfTypes(types: Type[], excludeKinds: TypeFlags): TypeFlags { + function getPropagatingFlagsOfTypes(types: ReadonlyArray, excludeKinds: TypeFlags): TypeFlags { let result: TypeFlags = 0; for (const type of types) { if (!(type.flags & excludeKinds)) { @@ -7804,7 +7806,7 @@ namespace ts { return result & TypeFlags.PropagatingFlags; } - function createTypeReference(target: GenericType, typeArguments: Type[] | undefined): TypeReference { + function createTypeReference(target: GenericType, typeArguments: ReadonlyArray | undefined): TypeReference { const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { @@ -8251,7 +8253,7 @@ namespace ts { /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ - function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: Type[]): ObjectType { + function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: ReadonlyArray): ObjectType { return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType; } @@ -8330,7 +8332,7 @@ namespace ts { return tupleTypes[arity] || (tupleTypes[arity] = createTupleTypeOfArity(arity)); } - function createTupleType(elementTypes: Type[]) { + function createTupleType(elementTypes: ReadonlyArray) { return createTypeReference(getTupleTypeOfArity(elementTypes.length), elementTypes); } @@ -8346,7 +8348,7 @@ namespace ts { return type.id; } - function containsType(types: Type[], type: Type): boolean { + function containsType(types: ReadonlyArray, type: Type): boolean { return binarySearch(types, type, getTypeId, compareValues) >= 0; } @@ -8410,14 +8412,14 @@ namespace ts { // Add the given types to the given type set. Order is preserved, duplicates are removed, // and nested types of the given kind are flattened into the set. - function addTypesToUnion(typeSet: Type[], includes: TypeFlags, types: Type[]): TypeFlags { + function addTypesToUnion(typeSet: Type[], includes: TypeFlags, types: ReadonlyArray): TypeFlags { for (const type of types) { includes = addTypeToUnion(typeSet, includes, type); } return includes; } - function containsIdenticalType(types: Type[], type: Type) { + function containsIdenticalType(types: ReadonlyArray, type: Type) { for (const t of types) { if (isTypeIdenticalTo(t, type)) { return true; @@ -8426,7 +8428,7 @@ namespace ts { return false; } - function isSubtypeOfAny(source: Type, targets: Type[]): boolean { + function isSubtypeOfAny(source: Type, targets: ReadonlyArray): boolean { for (const target of targets) { if (source !== target && isTypeSubtypeOf(source, target) && ( !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || @@ -8438,7 +8440,7 @@ namespace ts { return false; } - function isSetOfLiteralsFromSameEnum(types: Type[]): boolean { + function isSetOfLiteralsFromSameEnum(types: ReadonlyArray): boolean { const first = types[0]; if (first.flags & TypeFlags.EnumLiteral) { const firstEnum = getParentOfSymbol(first.symbol); @@ -8490,7 +8492,7 @@ namespace ts { // expression constructs such as array literals and the || and ?: operators). Named types can // circularly reference themselves and therefore cannot be subtype reduced during their declaration. // For example, "type Item = string | (() => Item" is a named type that circularly references itself. - function getUnionType(types: Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getUnionType(types: ReadonlyArray, unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): Type { if (types.length === 0) { return neverType; } @@ -8557,7 +8559,7 @@ namespace ts { } // This function assumes the constituent type list is sorted and deduplicated. - function getUnionTypeFromSortedList(types: Type[], unionOfUnitTypes: TypeFlags, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getUnionTypeFromSortedList(types: Type[], unionOfUnitTypes: TypeFlags, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): Type { if (types.length === 0) { return neverType; } @@ -8618,7 +8620,7 @@ namespace ts { // Add the given types to the given type set. Order is preserved, freshness is removed from literal // types, duplicates are removed, and nested types of the given kind are flattened into the set. - function addTypesToIntersection(typeSet: Type[], includes: TypeFlags, types: Type[]) { + function addTypesToIntersection(typeSet: Type[], includes: TypeFlags, types: ReadonlyArray) { for (const type of types) { includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type)); } @@ -8673,7 +8675,7 @@ namespace ts { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getIntersectionType(types: ReadonlyArray, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): Type { const typeSet: Type[] = []; const includes = addTypesToIntersection(typeSet, 0, types); if (includes & TypeFlags.Never) { @@ -9576,9 +9578,9 @@ namespace ts { } } - function instantiateList(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[]; - function instantiateList(items: T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] | undefined; - function instantiateList(items: T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] | undefined { + function instantiateList(items: ReadonlyArray, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): ReadonlyArray; + function instantiateList(items: ReadonlyArray | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): ReadonlyArray | undefined; + function instantiateList(items: ReadonlyArray | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): ReadonlyArray | undefined { if (items && items.length) { for (let i = 0; i < items.length; i++) { const item = items[i]; @@ -9596,14 +9598,14 @@ namespace ts { return items; } - function instantiateTypes(types: Type[], mapper: TypeMapper): Type[]; - function instantiateTypes(types: Type[] | undefined, mapper: TypeMapper): Type[] | undefined; - function instantiateTypes(types: Type[] | undefined, mapper: TypeMapper) { - return instantiateList(types, mapper, instantiateType); + function instantiateTypes(types: ReadonlyArray, mapper: TypeMapper): ReadonlyArray; + function instantiateTypes(types: ReadonlyArray | undefined, mapper: TypeMapper): ReadonlyArray | undefined; + function instantiateTypes(types: ReadonlyArray | undefined, mapper: TypeMapper): ReadonlyArray | undefined { + return instantiateList(types, mapper, instantiateType); } - function instantiateSignatures(signatures: Signature[], mapper: TypeMapper): Signature[] { - return instantiateList(signatures, mapper, instantiateSignature); + function instantiateSignatures(signatures: ReadonlyArray, mapper: TypeMapper): ReadonlyArray { + return instantiateList(signatures, mapper, instantiateSignature); } function makeUnaryTypeMapper(source: Type, target: Type) { @@ -9614,7 +9616,7 @@ namespace ts { return (t: Type) => t === source1 ? target1 : t === source2 ? target2 : t; } - function makeArrayTypeMapper(sources: Type[], targets: Type[] | undefined) { + function makeArrayTypeMapper(sources: ReadonlyArray, targets: ReadonlyArray | undefined) { return (t: Type) => { for (let i = 0; i < sources.length; i++) { if (t === sources[i]) { @@ -9625,14 +9627,14 @@ namespace ts { }; } - function createTypeMapper(sources: TypeParameter[], targets: Type[] | undefined): TypeMapper { + function createTypeMapper(sources: ReadonlyArray, targets: ReadonlyArray | undefined): TypeMapper { Debug.assert(targets === undefined || sources.length === targets.length); return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : makeArrayTypeMapper(sources, targets); } - function createTypeEraser(sources: TypeParameter[]): TypeMapper { + function createTypeEraser(sources: ReadonlyArray): TypeMapper { return createTypeMapper(sources, /*targets*/ undefined); } @@ -9640,7 +9642,7 @@ namespace ts { * Maps forward-references to later types parameters to the empty object type. * This is used during inference when instantiating type parameter defaults. */ - function createBackreferenceMapper(typeParameters: TypeParameter[], index: number): TypeMapper { + function createBackreferenceMapper(typeParameters: ReadonlyArray, index: number): TypeMapper { return t => typeParameters.indexOf(t) >= index ? emptyObjectType : t; } @@ -12404,7 +12406,7 @@ namespace ts { } } - function createInferenceContext(typeParameters: TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext { + function createInferenceContext(typeParameters: ReadonlyArray, signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext { const inferences = baseInferences ? baseInferences.map(cloneInferenceInfo) : typeParameters.map(createInferenceInfo); const context = mapper as InferenceContext; context.typeParameters = typeParameters; @@ -14247,7 +14249,7 @@ namespace ts { if (!targetType) { // Target type is type of construct signature - let constructSignatures: Signature[] | undefined; + let constructSignatures: ReadonlyArray | undefined; if (getObjectFlags(rightType) & ObjectFlags.Interface) { constructSignatures = resolveDeclaredMembers(rightType).declaredConstructSignatures; } @@ -16444,7 +16446,7 @@ namespace ts { return links.resolvedSymbol; } - function instantiateJsxSignatures(node: JsxOpeningLikeElement, signatures: Signature[]) { + function instantiateJsxSignatures(node: JsxOpeningLikeElement, signatures: ReadonlyArray) { const instantiatedSignatures = []; let candidateForTypeArgumentError: Signature | undefined; let hasTypeArgumentError: boolean = !!node.typeArguments; @@ -17674,7 +17676,7 @@ namespace ts { // interface B extends A { (x: 'foo'): string } // const b: B; // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] - function reorderCandidates(signatures: Signature[], result: Signature[]): void { + function reorderCandidates(signatures: ReadonlyArray, result: Signature[]): void { let lastParent: Node | undefined; let lastSymbol: Symbol | undefined; let cutoffIndex = 0; @@ -17883,7 +17885,7 @@ namespace ts { // Above, the type of the 'value' parameter is inferred to be 'A'. const contextualSignature = getSingleCallSignature(instantiatedType); const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? - getOrCreateTypeFromSignature(getSignatureInstantiation(contextualSignature, contextualSignature.typeParameters, isInJavaScriptFile(node))) : + getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : instantiatedType; const inferenceTargetType = getReturnTypeOfSignature(signature); // Inferences made from return types have lower priority than all other inferences. @@ -18373,7 +18375,7 @@ namespace ts { } } - function getTypeArgumentArityError(node: Node, signatures: Signature[], typeArguments: NodeArray) { + function getTypeArgumentArityError(node: Node, signatures: ReadonlyArray, typeArguments: NodeArray) { let min = Infinity; let max = -Infinity; for (const sig of signatures) { @@ -18384,7 +18386,7 @@ namespace ts { return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length); } - function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[] | undefined, fallbackError?: DiagnosticMessage): Signature { + function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray, candidatesOutArray: Signature[] | undefined, fallbackError?: DiagnosticMessage): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); @@ -18969,7 +18971,7 @@ namespace ts { * but is receiving too many arguments as part of the decorator invocation. * In those cases, a user may have meant to *call* the expression before using it as a decorator. */ - function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: Signature[]) { + function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: ReadonlyArray) { return signatures.length && every(signatures, signature => signature.minArgumentCount === 0 && !signature.hasRestParameter && @@ -21570,12 +21572,12 @@ namespace ts { checkDecorators(node); } - function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]): Type[] { + function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: ReadonlyArray): Type[] { return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isInJavaScriptFile(node)); } - function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]): boolean { + function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: ReadonlyArray): boolean { let typeArguments: Type[] | undefined; let mapper: TypeMapper | undefined; let result = true; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 65856ca23f9..e8b957fe704 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2854,7 +2854,7 @@ namespace ts { getPropertiesOfType(type: Type): Symbol[]; getPropertyOfType(type: Type, propertyName: string): Symbol | undefined; getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined; - getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; + getSignaturesOfType(type: Type, kind: SignatureKind): ReadonlyArray; getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined; getBaseTypes(type: InterfaceType): BaseType[]; getBaseTypeOfLiteralType(type: Type): Type; @@ -3735,7 +3735,7 @@ namespace ts { symbol: Symbol; // Symbol associated with type (if any) pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any) aliasSymbol?: Symbol; // Alias associated with type - aliasTypeArguments?: Type[]; // Alias type arguments (if any) + aliasTypeArguments?: ReadonlyArray; // Alias type arguments (if any) /* @internal */ wildcardInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type } @@ -3829,7 +3829,7 @@ namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; // Type reference target - typeArguments?: Type[]; // Type reference type arguments (undefined if none) + typeArguments?: ReadonlyArray; // Type reference type arguments (undefined if none) } /* @internal */ @@ -3906,8 +3906,8 @@ namespace ts { export interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties - callSignatures: Signature[]; // Call signatures of type - constructSignatures: Signature[]; // Construct signatures of type + callSignatures: ReadonlyArray; // Call signatures of type + constructSignatures: ReadonlyArray; // Construct signatures of type stringIndexInfo?: IndexInfo; // String indexing info numberIndexInfo?: IndexInfo; // Numeric indexing info } @@ -4032,8 +4032,8 @@ namespace ts { export interface Signature { declaration?: SignatureDeclaration | JSDocSignature; // Originating declaration - typeParameters?: TypeParameter[]; // Type parameters (undefined if non-generic) - parameters: Symbol[]; // Parameters + typeParameters?: ReadonlyArray; // Type parameters (undefined if non-generic) + parameters: ReadonlyArray; // Parameters /* @internal */ thisParameter?: Symbol; // symbol of this-type parameter /* @internal */ @@ -4132,11 +4132,11 @@ namespace ts { /* @internal */ export interface InferenceContext extends TypeMapper { - typeParameters: TypeParameter[]; // Type parameters for which inferences are made - signature?: Signature; // Generic signature for which inferences are made (if any) - inferences: InferenceInfo[]; // Inferences made for each type parameter - flags: InferenceFlags; // Inference flags - compareTypes: TypeComparer; // Type comparer function + typeParameters: ReadonlyArray; // Type parameters for which inferences are made + signature?: Signature; // Generic signature for which inferences are made (if any) + inferences: InferenceInfo[]; // Inferences made for each type parameter + flags: InferenceFlags; // Inference flags + compareTypes: TypeComparer; // Type comparer function } /* @internal */ diff --git a/src/services/services.ts b/src/services/services.ts index 24feaac17c6..2e275813585 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -391,10 +391,10 @@ namespace ts { getApparentProperties(): Symbol[] { return this.checker.getAugmentedPropertiesOfType(this); } - getCallSignatures(): Signature[] { + getCallSignatures(): ReadonlyArray { return this.checker.getSignaturesOfType(this, SignatureKind.Call); } - getConstructSignatures(): Signature[] { + getConstructSignatures(): ReadonlyArray { return this.checker.getSignaturesOfType(this, SignatureKind.Construct); } getStringIndexType(): Type | undefined { diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 2945d641c09..5eb26dc21d6 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -600,7 +600,7 @@ namespace ts.SymbolDisplay { } } - function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags = TypeFormatFlags.None) { + function addSignatureDisplayParts(signature: Signature, allSignatures: ReadonlyArray, flags = TypeFormatFlags.None) { addRange(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); if (allSignatures.length > 1) { displayParts.push(spacePart()); diff --git a/src/services/types.ts b/src/services/types.ts index 9ae51a4ea61..be897f20cd4 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -44,8 +44,8 @@ namespace ts { getProperties(): Symbol[]; getProperty(propertyName: string): Symbol | undefined; getApparentProperties(): Symbol[]; - getCallSignatures(): Signature[]; - getConstructSignatures(): Signature[]; + getCallSignatures(): ReadonlyArray; + getConstructSignatures(): ReadonlyArray; getStringIndexType(): Type | undefined; getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 78ad4d58c08..9ff2d42228d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2544,7 +2544,7 @@ declare namespace ts { getPropertiesOfType(type: Type): Symbol[]; getPropertyOfType(type: Type, propertyName: string): Symbol | undefined; getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined; - getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; + getSignaturesOfType(type: Type, kind: SignatureKind): ReadonlyArray; getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined; getBaseTypes(type: InterfaceType): BaseType[]; getBaseTypeOfLiteralType(type: Type): Type; @@ -3246,7 +3246,7 @@ declare namespace ts { symbol: Symbol; pattern?: DestructuringPattern; aliasSymbol?: Symbol; - aliasTypeArguments?: Type[]; + aliasTypeArguments?: ReadonlyArray; wildcardInstantiation?: Type; } interface IntrinsicType extends Type { @@ -3317,7 +3317,7 @@ declare namespace ts { */ interface TypeReference extends ObjectType { target: GenericType; - typeArguments?: Type[]; + typeArguments?: ReadonlyArray; } enum Variance { Invariant = 0, @@ -3367,8 +3367,8 @@ declare namespace ts { interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; properties: Symbol[]; - callSignatures: Signature[]; - constructSignatures: Signature[]; + callSignatures: ReadonlyArray; + constructSignatures: ReadonlyArray; stringIndexInfo?: IndexInfo; numberIndexInfo?: IndexInfo; } @@ -3447,8 +3447,8 @@ declare namespace ts { } interface Signature { declaration?: SignatureDeclaration | JSDocSignature; - typeParameters?: TypeParameter[]; - parameters: Symbol[]; + typeParameters?: ReadonlyArray; + parameters: ReadonlyArray; thisParameter?: Symbol; resolvedReturnType?: Type; resolvedTypePredicate?: TypePredicate; @@ -3514,7 +3514,7 @@ declare namespace ts { } type TypeComparer = (s: Type, t: Type, reportErrors?: boolean) => Ternary; interface InferenceContext extends TypeMapper { - typeParameters: TypeParameter[]; + typeParameters: ReadonlyArray; signature?: Signature; inferences: InferenceInfo[]; flags: InferenceFlags; @@ -9800,8 +9800,8 @@ declare namespace ts { getProperties(): Symbol[]; getProperty(propertyName: string): Symbol | undefined; getApparentProperties(): Symbol[]; - getCallSignatures(): Signature[]; - getConstructSignatures(): Signature[]; + getCallSignatures(): ReadonlyArray; + getConstructSignatures(): ReadonlyArray; getStringIndexType(): Type | undefined; getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8bb1efe058b..77bb50c3065 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1814,7 +1814,7 @@ declare namespace ts { getPropertiesOfType(type: Type): Symbol[]; getPropertyOfType(type: Type, propertyName: string): Symbol | undefined; getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined; - getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; + getSignaturesOfType(type: Type, kind: SignatureKind): ReadonlyArray; getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined; getBaseTypes(type: InterfaceType): BaseType[]; getBaseTypeOfLiteralType(type: Type): Type; @@ -2190,7 +2190,7 @@ declare namespace ts { symbol: Symbol; pattern?: DestructuringPattern; aliasSymbol?: Symbol; - aliasTypeArguments?: Type[]; + aliasTypeArguments?: ReadonlyArray; } interface LiteralType extends Type { value: string | number; @@ -2255,7 +2255,7 @@ declare namespace ts { */ interface TypeReference extends ObjectType { target: GenericType; - typeArguments?: Type[]; + typeArguments?: ReadonlyArray; } interface GenericType extends InterfaceType, TypeReference { } @@ -2315,8 +2315,8 @@ declare namespace ts { } interface Signature { declaration?: SignatureDeclaration | JSDocSignature; - typeParameters?: TypeParameter[]; - parameters: Symbol[]; + typeParameters?: ReadonlyArray; + parameters: ReadonlyArray; } enum IndexKind { String = 0, @@ -4599,8 +4599,8 @@ declare namespace ts { getProperties(): Symbol[]; getProperty(propertyName: string): Symbol | undefined; getApparentProperties(): Symbol[]; - getCallSignatures(): Signature[]; - getConstructSignatures(): Signature[]; + getCallSignatures(): ReadonlyArray; + getConstructSignatures(): ReadonlyArray; getStringIndexType(): Type | undefined; getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; From 40899eaf5b91440625c80b3ee58b481326f1ec0d Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 21 Jun 2018 09:57:52 -0700 Subject: [PATCH 23/27] Error on 'const' in class expression (#25125) --- src/compiler/checker.ts | 2 +- .../reference/constInClassExpression.errors.txt | 10 ++++++++++ tests/baselines/reference/constInClassExpression.js | 13 +++++++++++++ .../reference/constInClassExpression.symbols | 9 +++++++++ .../reference/constInClassExpression.types | 11 +++++++++++ tests/cases/compiler/constInClassExpression.ts | 3 +++ 6 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/constInClassExpression.errors.txt create mode 100644 tests/baselines/reference/constInClassExpression.js create mode 100644 tests/baselines/reference/constInClassExpression.symbols create mode 100644 tests/baselines/reference/constInClassExpression.types create mode 100644 tests/cases/compiler/constInClassExpression.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 813dc5c6345..648439f06b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27349,7 +27349,7 @@ namespace ts { } switch (modifier.kind) { case SyntaxKind.ConstKeyword: - if (node.kind !== SyntaxKind.EnumDeclaration && node.parent.kind === SyntaxKind.ClassDeclaration) { + if (node.kind !== SyntaxKind.EnumDeclaration) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } break; diff --git a/tests/baselines/reference/constInClassExpression.errors.txt b/tests/baselines/reference/constInClassExpression.errors.txt new file mode 100644 index 00000000000..b3b66cba3a5 --- /dev/null +++ b/tests/baselines/reference/constInClassExpression.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/constInClassExpression.ts(2,11): error TS1248: A class member cannot have the 'const' keyword. + + +==== tests/cases/compiler/constInClassExpression.ts (1 errors) ==== + let C = class { + const a = 4; + ~ +!!! error TS1248: A class member cannot have the 'const' keyword. + }; + \ No newline at end of file diff --git a/tests/baselines/reference/constInClassExpression.js b/tests/baselines/reference/constInClassExpression.js new file mode 100644 index 00000000000..1da4605687a --- /dev/null +++ b/tests/baselines/reference/constInClassExpression.js @@ -0,0 +1,13 @@ +//// [constInClassExpression.ts] +let C = class { + const a = 4; +}; + + +//// [constInClassExpression.js] +var C = /** @class */ (function () { + function class_1() { + this.a = 4; + } + return class_1; +}()); diff --git a/tests/baselines/reference/constInClassExpression.symbols b/tests/baselines/reference/constInClassExpression.symbols new file mode 100644 index 00000000000..7468772edfb --- /dev/null +++ b/tests/baselines/reference/constInClassExpression.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/constInClassExpression.ts === +let C = class { +>C : Symbol(C, Decl(constInClassExpression.ts, 0, 3)) + + const a = 4; +>a : Symbol(C.a, Decl(constInClassExpression.ts, 0, 15)) + +}; + diff --git a/tests/baselines/reference/constInClassExpression.types b/tests/baselines/reference/constInClassExpression.types new file mode 100644 index 00000000000..1efe8527e04 --- /dev/null +++ b/tests/baselines/reference/constInClassExpression.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/constInClassExpression.ts === +let C = class { +>C : typeof C +>class { const a = 4;} : typeof C + + const a = 4; +>a : number +>4 : 4 + +}; + diff --git a/tests/cases/compiler/constInClassExpression.ts b/tests/cases/compiler/constInClassExpression.ts new file mode 100644 index 00000000000..b00b085e079 --- /dev/null +++ b/tests/cases/compiler/constInClassExpression.ts @@ -0,0 +1,3 @@ +let C = class { + const a = 4; +}; From 43d0794ba355efb8fe257ef5fffc1db186c37cd0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 21 Jun 2018 10:01:39 -0700 Subject: [PATCH 24/27] Fix crash when binding jsdoc-style inner namepaths (#25106) * getDeclarationIdentifier handles undefined name getNameOfDeclaration actually doesn't handle all declarations, only those that produce names that could be reasonably used as an identifier. Until now, getDeclarationIdentifier assumed that getNameOfDeclaration always returned a name. This caused crashes whenever we tried to get the name of something like a Constructor. * Add test and baselines * getNameOfDeclaration can return undefined This requires all callers to handle it, which turns out now to be too disruptive. * Fix lint --- src/compiler/checker.ts | 23 +++++++-------- src/compiler/factory.ts | 8 +++--- src/compiler/utilities.ts | 23 ++++++++------- src/services/codefixes/inferFromUsage.ts | 5 ++-- src/services/completions.ts | 4 +-- src/services/findAllReferences.ts | 5 ++-- src/services/formatting/formatting.ts | 5 +++- src/services/navigateTo.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 8 +++--- tests/baselines/reference/api/typescript.d.ts | 4 +-- .../typedefInnerNamepaths.errors.txt | 28 +++++++++++++++++++ .../reference/typedefInnerNamepaths.symbols | 14 ++++++++++ .../reference/typedefInnerNamepaths.types | 14 ++++++++++ .../jsdoc/typedefInnerNamepaths.ts | 13 +++++++++ 14 files changed, 113 insertions(+), 43 deletions(-) create mode 100644 tests/baselines/reference/typedefInnerNamepaths.errors.txt create mode 100644 tests/baselines/reference/typedefInnerNamepaths.symbols create mode 100644 tests/baselines/reference/typedefInnerNamepaths.types create mode 100644 tests/cases/conformance/jsdoc/typedefInnerNamepaths.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 648439f06b7..03742128935 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22807,11 +22807,7 @@ namespace ts { addDiagnostic(UnusedKind.Local, createDiagnosticForNode(node, message, name)); } - function parameterNameStartsWithUnderscore(parameterName: DeclarationName) { - return parameterName && isIdentifierThatStartsWithUnderScore(parameterName); - } - - function isIdentifierThatStartsWithUnderScore(node: Node) { + function isIdentifierThatStartsWithUnderscore(node: Node) { return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; } @@ -22859,7 +22855,7 @@ namespace ts { const typeParameters = getEffectiveTypeParameterDeclarations(node); if (!(node.flags & NodeFlags.Ambient) && last(getSymbolOfNode(node).declarations) === node) { for (const typeParameter of typeParameters) { - if (!(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) { + if (!(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name)) { addDiagnostic(UnusedKind.Parameter, createDiagnosticForNode(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol))); } } @@ -22897,7 +22893,7 @@ namespace ts { for (const declaration of local.declarations) { if (isAmbientModule(declaration) || - (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderScore(declaration.name!)) { + (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!)) { continue; } @@ -22916,9 +22912,9 @@ namespace ts { } else { const parameter = local.valueDeclaration && tryGetRootParameterDeclaration(local.valueDeclaration); - if (parameter) { - const name = getNameOfDeclaration(local.valueDeclaration); - if (!isParameterPropertyDeclaration(parameter) && !parameterIsThisKeyword(parameter) && !parameterNameStartsWithUnderscore(name)) { + const name = getNameOfDeclaration(local.valueDeclaration); + if (parameter && name) { + if (!isParameterPropertyDeclaration(parameter) && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name)) { addDiagnostic(UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); } } @@ -24213,18 +24209,19 @@ namespace ts { } const propDeclaration = prop.valueDeclaration; + const name = getNameOfDeclaration(propDeclaration); // index is numeric and property name is not valid numeric literal - if (indexKind === IndexKind.Number && !(propDeclaration ? isNumericName(getNameOfDeclaration(propDeclaration)) : isNumericLiteralName(prop.escapedName))) { + if (indexKind === IndexKind.Number && !(name ? isNumericName(name) : isNumericLiteralName(prop.escapedName))) { return; } // perform property check if property or indexer is declared in 'type' // this allows us to rule out cases when both property and indexer are inherited from the base class let errorNode: Node | undefined; - if (propDeclaration && + if (propDeclaration && name && (propDeclaration.kind === SyntaxKind.BinaryExpression || - getNameOfDeclaration(propDeclaration).kind === SyntaxKind.ComputedPropertyName || + name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol)) { errorNode = propDeclaration; } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 91ff766678a..7b8a50ef603 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -194,10 +194,10 @@ namespace ts { } /** Create a unique name generated for a node. */ - export function getGeneratedNameForNode(node: Node): Identifier; - /* @internal */ export function getGeneratedNameForNode(node: Node, flags: GeneratedIdentifierFlags): Identifier; // tslint:disable-line unified-signatures - export function getGeneratedNameForNode(node: Node, flags?: GeneratedIdentifierFlags): Identifier { - const name = createIdentifier(isIdentifier(node) ? idText(node) : ""); + export function getGeneratedNameForNode(node: Node | undefined): Identifier; + /* @internal */ export function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags): Identifier; // tslint:disable-line unified-signatures + export function getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags): Identifier { + const name = createIdentifier(node && isIdentifier(node) ? idText(node) : ""); name.autoGenerateFlags = GeneratedIdentifierFlags.Node | flags!; name.autoGenerateId = nextAutoGenerateId; name.original = node; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7c2a13abbf7..93415815e74 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -745,8 +745,8 @@ namespace ts { // Return display name of an identifier // Computed property names will just be emitted as "[]", where is the source // text of the expression in the computed property. - export function declarationNameToString(name: DeclarationName | QualifiedName) { - return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); + export function declarationNameToString(name: DeclarationName | QualifiedName | undefined) { + return !name || getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); } export function getNameFromIndexInfo(info: IndexInfo): string | undefined { @@ -4858,7 +4858,7 @@ namespace ts { function getDeclarationIdentifier(node: Declaration | Expression): Identifier | undefined { const name = getNameOfDeclaration(node); - return isIdentifier(name) ? name : undefined; + return name && isIdentifier(name) ? name : undefined; } export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { @@ -4870,16 +4870,15 @@ namespace ts { return !!(node as NamedDeclaration).name; // A 'name' property should always be a DeclarationName. } - // TODO: GH#18217 This is often used as if it returns a defined result - export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName { + export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined { if (!declaration) { - return undefined!; + return undefined; } switch (declaration.kind) { case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: if (!(declaration as ClassExpression | FunctionExpression).name) { - return getAssignedName(declaration)!; + return getAssignedName(declaration); } break; case SyntaxKind.Identifier: @@ -4901,19 +4900,19 @@ namespace ts { case SpecialPropertyAssignmentKind.PrototypeProperty: return (expr.left as PropertyAccessExpression).name; default: - return undefined!; + return undefined; } } case SyntaxKind.JSDocCallbackTag: - return (declaration as JSDocCallbackTag).name!; + return (declaration as JSDocCallbackTag).name; case SyntaxKind.JSDocTypedefTag: - return getNameOfJSDocTypedef(declaration as JSDocTypedefTag)!; + return getNameOfJSDocTypedef(declaration as JSDocTypedefTag); case SyntaxKind.ExportAssignment: { const { expression } = declaration as ExportAssignment; - return isIdentifier(expression) ? expression : undefined!; + return isIdentifier(expression) ? expression : undefined; } } - return (declaration as NamedDeclaration).name!; + return (declaration as NamedDeclaration).name; } function getAssignedName(node: Node): DeclarationName | undefined { diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index c58c001b403..3e26e4cdd32 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -33,8 +33,9 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); let declaration!: Declaration | undefined; const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeenseen*/ returnTrue); }); - return changes.length === 0 ? undefined - : [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), getNameOfDeclaration(declaration!).getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)]; + const name = getNameOfDeclaration(declaration!); + return !name || changes.length === 0 ? undefined + : [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), name.getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)]; }, fixIds: [fixId], getAllCodeActions(context) { diff --git a/src/services/completions.ts b/src/services/completions.ts index e31ac4e81f3..21d704661b2 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1122,7 +1122,7 @@ namespace ts.Completions { // If this is e.g. [Symbol.iterator], add a completion for `Symbol`. const symbolSymbol = firstDefined(symbol.declarations, decl => { const name = getNameOfDeclaration(decl); - const leftName = name.kind === SyntaxKind.ComputedPropertyName ? getLeftMostName(name.expression) : undefined; + const leftName = name && name.kind === SyntaxKind.ComputedPropertyName ? getLeftMostName(name.expression) : undefined; return leftName && typeChecker.getSymbolAtLocation(leftName); }); if (symbolSymbol) { @@ -1966,7 +1966,7 @@ namespace ts.Completions { // NOTE: if one only performs this step when m.name is an identifier, // things like '__proto__' are not filtered out. const name = getNameOfDeclaration(m); - existingName = isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; + existingName = name && isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } existingMemberNames.set(existingName!, true); // TODO: GH#18217 diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 46dd83851c1..0fbcd5cd6e9 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -981,6 +981,7 @@ namespace ts.FindAllReferences.Core { function getReferenceForShorthandProperty({ flags, valueDeclaration }: Symbol, search: Search, state: State): void { const shorthandValueSymbol = state.checker.getShorthandAssignmentValueSymbol(valueDeclaration)!; + const name = getNameOfDeclaration(valueDeclaration); /* * Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment * has two meanings: property name and property value. Therefore when we do findAllReference at the position where @@ -988,8 +989,8 @@ namespace ts.FindAllReferences.Core { * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the * position of property accessing, the referenceEntry of such position will be handled in the first case. */ - if (!(flags & SymbolFlags.Transient) && search.includes(shorthandValueSymbol)) { - addReference(getNameOfDeclaration(valueDeclaration), shorthandValueSymbol, state); + if (!(flags & SymbolFlags.Transient) && name && search.includes(shorthandValueSymbol)) { + addReference(name, shorthandValueSymbol, state); } } diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index eeec4b15ea7..f37fb1bc5dd 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -512,7 +512,10 @@ namespace ts.formatting { // falls through case SyntaxKind.PropertyDeclaration: case SyntaxKind.Parameter: - return getNameOfDeclaration(node).kind; + const name = getNameOfDeclaration(node); + if (name) { + return name.kind; + } } } diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 723d7f59b3a..dc03c736f3c 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -113,7 +113,7 @@ namespace ts.NavigateTo { // First, if we started with a computed property name, then add all but the last // portion into the container array. const name = getNameOfDeclaration(declaration); - if (name.kind === SyntaxKind.ComputedPropertyName && !tryAddComputedPropertyName(name.expression, containers, /*includeLastPortion*/ false)) { + if (name && name.kind === SyntaxKind.ComputedPropertyName && !tryAddComputedPropertyName(name.expression, containers, /*includeLastPortion*/ false)) { return undefined; } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 9ff2d42228d..a98241125a5 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6106,7 +6106,7 @@ declare namespace ts { function isLateVisibilityPaintedStatement(node: Node): node is LateVisibilityPaintedStatement; function isAnyImportOrReExport(node: Node): node is AnyImportOrReExport; function getEnclosingBlockScopeContainer(node: Node): Node; - function declarationNameToString(name: DeclarationName | QualifiedName): string; + function declarationNameToString(name: DeclarationName | QualifiedName | undefined): string; function getNameFromIndexInfo(info: IndexInfo): string | undefined; function getTextOfPropertyName(name: PropertyName): __String; function entityNameToString(name: EntityNameOrEntityNameExpression): string; @@ -6685,7 +6685,7 @@ declare namespace ts { function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName; }; - function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName; + function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. * @@ -7702,8 +7702,8 @@ declare namespace ts { /** Create a unique name based on the supplied text. This does not consider names injected by the transformer. */ function createFileLevelUniqueName(text: string): Identifier; /** Create a unique name generated for a node. */ - function getGeneratedNameForNode(node: Node): Identifier; - function getGeneratedNameForNode(node: Node, flags: GeneratedIdentifierFlags): Identifier; + function getGeneratedNameForNode(node: Node | undefined): Identifier; + function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags): Identifier; function createToken(token: TKind): Token; function createSuper(): SuperExpression; function createThis(): ThisExpression & Token; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 77bb50c3065..9995fec649c 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3188,7 +3188,7 @@ declare namespace ts { */ function unescapeIdentifier(id: string): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined; - function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName; + function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. * @@ -3623,7 +3623,7 @@ declare namespace ts { /** Create a unique name based on the supplied text. This does not consider names injected by the transformer. */ function createFileLevelUniqueName(text: string): Identifier; /** Create a unique name generated for a node. */ - function getGeneratedNameForNode(node: Node): Identifier; + function getGeneratedNameForNode(node: Node | undefined): Identifier; function createToken(token: TKind): Token; function createSuper(): SuperExpression; function createThis(): ThisExpression & Token; diff --git a/tests/baselines/reference/typedefInnerNamepaths.errors.txt b/tests/baselines/reference/typedefInnerNamepaths.errors.txt new file mode 100644 index 00000000000..179c36b0edd --- /dev/null +++ b/tests/baselines/reference/typedefInnerNamepaths.errors.txt @@ -0,0 +1,28 @@ +tests/cases/conformance/jsdoc/bug25104.js(1,7): error TS2300: Duplicate identifier 'C'. +tests/cases/conformance/jsdoc/bug25104.js(3,19): error TS1005: '}' expected. +tests/cases/conformance/jsdoc/bug25104.js(4,26): error TS2300: Duplicate identifier 'C'. +tests/cases/conformance/jsdoc/bug25104.js(6,18): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name. +tests/cases/conformance/jsdoc/bug25104.js(6,18): error TS1005: '}' expected. + + +==== tests/cases/conformance/jsdoc/bug25104.js (5 errors) ==== + class C { + ~ +!!! error TS2300: Duplicate identifier 'C'. + /** + * @typedef {C~A} C~B + ~ +!!! error TS1005: '}' expected. + * @typedef {object} C~A + ~ +!!! error TS2300: Duplicate identifier 'C'. + */ + /** @param {C~A} o */ + +!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name. + ~ +!!! error TS1005: '}' expected. + constructor(o) { + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/typedefInnerNamepaths.symbols b/tests/baselines/reference/typedefInnerNamepaths.symbols new file mode 100644 index 00000000000..2ddcf419734 --- /dev/null +++ b/tests/baselines/reference/typedefInnerNamepaths.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/jsdoc/bug25104.js === +class C { +>C : Symbol(C, Decl(bug25104.js, 0, 0)) + + /** + * @typedef {C~A} C~B + * @typedef {object} C~A + */ + /** @param {C~A} o */ + constructor(o) { +>o : Symbol(o, Decl(bug25104.js, 6, 16)) + } +} + diff --git a/tests/baselines/reference/typedefInnerNamepaths.types b/tests/baselines/reference/typedefInnerNamepaths.types new file mode 100644 index 00000000000..16e8ab556a7 --- /dev/null +++ b/tests/baselines/reference/typedefInnerNamepaths.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/jsdoc/bug25104.js === +class C { +>C : C + + /** + * @typedef {C~A} C~B + * @typedef {object} C~A + */ + /** @param {C~A} o */ + constructor(o) { +>o : any + } +} + diff --git a/tests/cases/conformance/jsdoc/typedefInnerNamepaths.ts b/tests/cases/conformance/jsdoc/typedefInnerNamepaths.ts new file mode 100644 index 00000000000..ee71909c2ed --- /dev/null +++ b/tests/cases/conformance/jsdoc/typedefInnerNamepaths.ts @@ -0,0 +1,13 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @Filename: bug25104.js +class C { + /** + * @typedef {C~A} C~B + * @typedef {object} C~A + */ + /** @param {C~A} o */ + constructor(o) { + } +} From e7b338e9432df2941993b7cd684954f900f2dbf6 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 21 Jun 2018 10:18:37 -0700 Subject: [PATCH 25/27] Don't treat a declaration as a type argument position (#25046) --- src/services/utilities.ts | 2 +- tests/cases/fourslash/signatureHelpOnDeclaration.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/signatureHelpOnDeclaration.ts diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e3f4f6523fb..481d20e91bd 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -948,7 +948,7 @@ namespace ts { token = findPrecedingToken(token.getFullStart(), sourceFile); if (!token || !isIdentifier(token)) return undefined; if (!remainingLessThanTokens) { - return { called: token, nTypeArguments }; + return isDeclarationName(token) ? undefined : { called: token, nTypeArguments }; } remainingLessThanTokens--; break; diff --git a/tests/cases/fourslash/signatureHelpOnDeclaration.ts b/tests/cases/fourslash/signatureHelpOnDeclaration.ts new file mode 100644 index 00000000000..7fc68174383 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnDeclaration.ts @@ -0,0 +1,6 @@ +/// + +////function f Date: Thu, 21 Jun 2018 10:19:14 -0700 Subject: [PATCH 26/27] Don't recommend to install '@types/foo' if that already exists (#24815) * Don't recommend to install '@types/foo' if that already exists * Add different extra diagnostic text if the @types package exists * Update API (#24966) --- src/compiler/checker.ts | 16 ++++++--- src/compiler/diagnosticMessages.json | 6 +++- .../reference/api/tsserverlibrary.d.ts | 1 + ...mplicitAny_typesForPackageExist.errors.txt | 35 +++++++++++++++++++ ...port_noImplicitAny_typesForPackageExist.js | 29 +++++++++++++++ ...noImplicitAny_typesForPackageExist.symbols | 14 ++++++++ ...t_noImplicitAny_typesForPackageExist.types | 14 ++++++++ ...port_noImplicitAny_typesForPackageExist.ts | 25 +++++++++++++ 8 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt create mode 100644 tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js create mode 100644 tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols create mode 100644 tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types create mode 100644 tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 03742128935..3867a26c023 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2283,16 +2283,24 @@ namespace ts { } function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { - const errorInfo = packageId && chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, - getMangledNameForScopedPackage(packageId.name)); + const errorInfo = packageId + ? chainDiagnosticMessages( + /*details*/ undefined, + typesPackageExists(packageId.name) + ? Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_0 + : Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, + getMangledNameForScopedPackage(packageId.name)) + : undefined; errorOrSuggestion(isError, errorNode, chainDiagnosticMessages( errorInfo, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, moduleReference, resolvedFileName)); } + function typesPackageExists(packageName: string): boolean { + return host.getSourceFiles().some(sf => !!sf.resolvedModules && !!forEachEntry(sf.resolvedModules, r => + r && r.packageId && r.packageId.name === getTypesPackageName(packageName))); + } // An external module with an 'export =' declaration resolves to the target of the 'export =' declaration, // and an external module with no 'export =' declaration resolves to the module itself. diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 24b3031b877..7d08fd5caf1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3636,7 +3636,7 @@ "category": "Message", "code": 6353 }, - + "Project '{0}' is up to date with .d.ts files from its dependencies": { "category": "Message", "code": 6354 @@ -3836,6 +3836,10 @@ "category": "Error", "code": 7039 }, + "If the '{0}' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/{0}`": { + "category": "Error", + "code": 7040 + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a98241125a5..ba313c2db5e 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5752,6 +5752,7 @@ declare namespace ts { Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports: DiagnosticMessage; Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead: DiagnosticMessage; Mapped_object_type_implicitly_has_an_any_template_type: DiagnosticMessage; + If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_0: DiagnosticMessage; You_cannot_rename_this_element: DiagnosticMessage; You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: DiagnosticMessage; import_can_only_be_used_in_a_ts_file: DiagnosticMessage; diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt new file mode 100644 index 00000000000..ef5997f8f5e --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt @@ -0,0 +1,35 @@ +/a.ts(2,25): error TS7016: Could not find a declaration file for module 'foo/sub'. '/node_modules/foo/sub.js' implicitly has an 'any' type. + If the 'foo' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/foo` +/a.ts(3,25): error TS7016: Could not find a declaration file for module 'bar/sub'. '/node_modules/bar/sub.js' implicitly has an 'any' type. + Try `npm install @types/bar` if it exists or add a new declaration (.d.ts) file containing `declare module 'bar';` + + +==== /a.ts (2 errors) ==== + import * as foo from "foo"; + import * as fooSub from "foo/sub"; + ~~~~~~~~~ +!!! error TS7016: Could not find a declaration file for module 'foo/sub'. '/node_modules/foo/sub.js' implicitly has an 'any' type. +!!! error TS7016: If the 'foo' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/foo` + import * as barSub from "bar/sub"; + ~~~~~~~~~ +!!! error TS7016: Could not find a declaration file for module 'bar/sub'. '/node_modules/bar/sub.js' implicitly has an 'any' type. +!!! error TS7016: Try `npm install @types/bar` if it exists or add a new declaration (.d.ts) file containing `declare module 'bar';` + +==== /node_modules/@types/foo/index.d.ts (0 errors) ==== + export const foo: number; + +==== /node_modules/@types/foo/package.json (0 errors) ==== + { "name": "@types/foo", "version": "1.2.3" } + +==== /node_modules/foo/sub.js (0 errors) ==== + const x = 0; + +==== /node_modules/foo/package.json (0 errors) ==== + { "name": "foo", "version": "1.2.3" } + +==== /node_modules/bar/sub.js (0 errors) ==== + const x = 0; + +==== /node_modules/bar/package.json (0 errors) ==== + { "name": "bar", "version": "1.2.3" } + \ No newline at end of file diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js new file mode 100644 index 00000000000..fe1a85730cd --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js @@ -0,0 +1,29 @@ +//// [tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts] //// + +//// [index.d.ts] +export const foo: number; + +//// [package.json] +{ "name": "@types/foo", "version": "1.2.3" } + +//// [sub.js] +const x = 0; + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [sub.js] +const x = 0; + +//// [package.json] +{ "name": "bar", "version": "1.2.3" } + +//// [a.ts] +import * as foo from "foo"; +import * as fooSub from "foo/sub"; +import * as barSub from "bar/sub"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols new file mode 100644 index 00000000000..59153d03f54 --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols @@ -0,0 +1,14 @@ +=== /a.ts === +import * as foo from "foo"; +>foo : Symbol(foo, Decl(a.ts, 0, 6)) + +import * as fooSub from "foo/sub"; +>fooSub : Symbol(fooSub, Decl(a.ts, 1, 6)) + +import * as barSub from "bar/sub"; +>barSub : Symbol(barSub, Decl(a.ts, 2, 6)) + +=== /node_modules/@types/foo/index.d.ts === +export const foo: number; +>foo : Symbol(foo, Decl(index.d.ts, 0, 12)) + diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types new file mode 100644 index 00000000000..9a6b7b7e690 --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types @@ -0,0 +1,14 @@ +=== /a.ts === +import * as foo from "foo"; +>foo : typeof foo + +import * as fooSub from "foo/sub"; +>fooSub : any + +import * as barSub from "bar/sub"; +>barSub : any + +=== /node_modules/@types/foo/index.d.ts === +export const foo: number; +>foo : number + diff --git a/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts b/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts new file mode 100644 index 00000000000..74e9da10804 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts @@ -0,0 +1,25 @@ +// @noImplicitReferences: true +// @strict: true + +// @Filename: /node_modules/@types/foo/index.d.ts +export const foo: number; + +// @Filename: /node_modules/@types/foo/package.json +{ "name": "@types/foo", "version": "1.2.3" } + +// @Filename: /node_modules/foo/sub.js +const x = 0; + +// @Filename: /node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /node_modules/bar/sub.js +const x = 0; + +// @Filename: /node_modules/bar/package.json +{ "name": "bar", "version": "1.2.3" } + +// @Filename: /a.ts +import * as foo from "foo"; +import * as fooSub from "foo/sub"; +import * as barSub from "bar/sub"; From 22fde1865795999e13cc08e557687d8a0c1e904d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 21 Jun 2018 10:43:01 -0700 Subject: [PATCH 27/27] Fix RWC baseline paths --- Jakefile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 7eb6852472b..8787a783ec2 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -67,10 +67,10 @@ Paths.tsserverLibraryDefinitionFile = "built/local/tsserverlibrary.d.ts"; Paths.baselines = {}; Paths.baselines.local = "tests/baselines/local"; Paths.baselines.localTest262 = "tests/baselines/test262/local"; -Paths.baselines.localRwc = "tests/baselines/rwc/local"; +Paths.baselines.localRwc = "internal/baselines/rwc/local"; Paths.baselines.reference = "tests/baselines/reference"; Paths.baselines.referenceTest262 = "tests/baselines/test262/reference"; -Paths.baselines.referenceRwc = "tests/baselines/rwc/reference"; +Paths.baselines.referenceRwc = "internal/baselines/rwc/reference"; Paths.copyright = "CopyrightNotice.txt"; Paths.thirdParty = "ThirdPartyNoticeText.txt"; Paths.processDiagnosticMessagesJs = "scripts/processDiagnosticMessages.js";