From 482a4d320dd7279a85b07f8564234d76d11762c6 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 24 Jun 2020 13:02:53 +0800 Subject: [PATCH 01/12] support overload atsignature --- src/compiler/binder.ts | 12 +- src/compiler/checker.ts | 7 + src/compiler/types.ts | 1 + .../fourslash/jsdocDeprecated_suggestion2.ts | 130 ++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion2.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ad35852c22865..3b497c87069bf 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -537,7 +537,17 @@ namespace ts { symbol.parent = parent; } - if (node.flags & NodeFlags.Deprecated) { + const hasDeprecated = !!(node.flags & NodeFlags.Deprecated); + if (symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) { + symbol.allSignatureDeprecated = hasDeprecated && (symbol.allSignatureDeprecated ?? true); + if (symbol.allSignatureDeprecated) { + symbol.flags |= SymbolFlags.Deprecated; + } + else { + symbol.flags &= ~SymbolFlags.Deprecated; + } + } + else if(hasDeprecated) { symbol.flags |= SymbolFlags.Deprecated; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba234e4981bef..b2ccf287e7c5f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27368,6 +27368,13 @@ namespace ts { return nonInferrableType; } + if (signature.declaration && ( + (isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration)) || + !signature.declaration.symbol.allSignatureDeprecated + ) && (signature.declaration.flags & NodeFlags.Deprecated)) { + errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, signatureToString(signature)); + } + if (node.expression.kind === SyntaxKind.SuperKeyword) { return voidType; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bc53c6484626e..110ce8d7c0cd8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4592,6 +4592,7 @@ namespace ts { /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments /* @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol + /* @internal */ allSignatureDeprecated?: boolean; // All signatures have the deprecated tag } /* @internal */ diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion2.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion2.ts new file mode 100644 index 0000000000000..ffcc933dd15a7 --- /dev/null +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion2.ts @@ -0,0 +1,130 @@ +/// + +//// declare function foo(a: string): number; +//// /** @deprecated */ +//// declare function foo(): undefined; +//// declare function foo (a?: string): number | undefined; +//// [|foo()|]; +//// foo(''); +//// foo; + +//// /** @deprecated */ +//// declare function bar(): number; +//// [|bar|](); +//// [|bar|]; + +//// /** @deprecated */ +//// declare function baz(): number; +//// /** @deprecated */ +//// declare function baz(): number | undefined; +//// [|baz|](); +//// [|baz|]; + +//// interface Foo { +//// /** @deprecated */ +//// (): void +//// (a: number): void +//// } +//// declare const f: Foo; +//// [|f()|]; +//// f(1); + +//// interface T { +//// createElement(): void +//// /** @deprecated */ +//// createElement(tag: 'xmp'): void; +//// } +//// declare const t: T; +//// t.createElement(); +//// [|t.createElement('xmp')|]; + +//// declare class C { +//// /** @deprecated */ +//// constructor (); +//// constructor(v: string) +//// } +//// C; +//// const c = [|new C()|]; + +//// interface Ca { +//// /** @deprecated */ +//// (): void +//// new (): void +//// } +//// interface Cb { +//// (): void +//// /** @deprecated */ +//// new (): string +//// } +//// declare const ca: Ca; +//// declare const cb: Cb; +//// ca; +//// cb; +//// [|ca()|]; +//// cb(); +//// new ca(); +//// [|new cb()|]; + +const ranges = test.ranges(); +verify.getSuggestionDiagnostics([ + { + message: "'(): undefined' is deprecated", + code: 6385, + range: ranges[0], + reportsDeprecated: true, + }, + { + message: "'bar' is deprecated", + code: 6385, + range: ranges[1], + reportsDeprecated: true, + }, + { + message: "'bar' is deprecated", + code: 6385, + range: ranges[2], + reportsDeprecated: true, + }, + { + message: "'baz' is deprecated", + code: 6385, + range: ranges[3], + reportsDeprecated: true, + }, + { + message: "'baz' is deprecated", + code: 6385, + range: ranges[4], + reportsDeprecated: true, + }, + { + message: "'(): void' is deprecated", + code: 6385, + range: ranges[5], + reportsDeprecated: true, + }, + { + message: `'(tag: "xmp"): void' is deprecated`, + code: 6385, + range: ranges[6], + reportsDeprecated: true, + }, + { + message: `'(): C' is deprecated`, + code: 6385, + range: ranges[7], + reportsDeprecated: true, + }, + { + message: `'(): void' is deprecated`, + code: 6385, + range: ranges[8], + reportsDeprecated: true, + }, + { + message: `'(): string' is deprecated`, + code: 6385, + range: ranges[9], + reportsDeprecated: true, + }, +]) From 82e0840e9fcb08ed4f73f512b411f089d1a124e3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 24 Jun 2020 11:15:44 -0700 Subject: [PATCH 02/12] Update src/compiler/binder.ts --- src/compiler/binder.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3b497c87069bf..0c465ca759696 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -547,7 +547,8 @@ namespace ts { symbol.flags &= ~SymbolFlags.Deprecated; } } - else if(hasDeprecated) { + else if (hasDeprecated) { + symbol.flags |= SymbolFlags.Deprecated; } From f292689f3106e6c145168b07fbaadd34ccc806c2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 24 Jun 2020 11:59:42 -0700 Subject: [PATCH 03/12] Update src/compiler/binder.ts --- src/compiler/binder.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 0c465ca759696..b5040b62cf085 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -548,7 +548,6 @@ namespace ts { } } else if (hasDeprecated) { - symbol.flags |= SymbolFlags.Deprecated; } From fcd722a0f10b7e2c4fede0f3cde7f5c2ad009412 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 25 Jun 2020 13:00:04 +0800 Subject: [PATCH 04/12] fix perf --- src/compiler/binder.ts | 25 +++++++--- src/compiler/checker.ts | 2 +- src/compiler/types.ts | 2 +- .../fourslash/jsdocDeprecated_suggestion3.ts | 49 +++++++++++++++++++ 4 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion3.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b5040b62cf085..9fd1703ead56d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -537,21 +537,30 @@ namespace ts { symbol.parent = parent; } + checkDeprecatedForSymbol(node, symbol); + return symbol; + } + + function checkDeprecatedForSymbol(node: Declaration, symbol: Symbol) { const hasDeprecated = !!(node.flags & NodeFlags.Deprecated); - if (symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) { - symbol.allSignatureDeprecated = hasDeprecated && (symbol.allSignatureDeprecated ?? true); - if (symbol.allSignatureDeprecated) { - symbol.flags |= SymbolFlags.Deprecated; - } - else { + const isSignatureLike = !!(symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)); + if (isSignatureLike) { + const hasSetDeprecated = symbol.allSignaturesDeprecated === undefined; + if (hasDeprecated && hasSetDeprecated) { + const allSignaturesDeprecated = every(filter(symbol.declarations, isFunctionLike), decl => !!(decl.flags & NodeFlags.Deprecated)); + symbol.allSignaturesDeprecated = allSignaturesDeprecated; + if (allSignaturesDeprecated) { + symbol.flags |= SymbolFlags.Deprecated; + } + } + else if (!hasDeprecated && !hasSetDeprecated) { + symbol.allSignaturesDeprecated = false; symbol.flags &= ~SymbolFlags.Deprecated; } } else if (hasDeprecated) { symbol.flags |= SymbolFlags.Deprecated; } - - return symbol; } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b2ccf287e7c5f..6b92695cfd3fd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27370,7 +27370,7 @@ namespace ts { if (signature.declaration && ( (isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration)) || - !signature.declaration.symbol.allSignatureDeprecated + !signature.declaration.symbol.allSignaturesDeprecated ) && (signature.declaration.flags & NodeFlags.Deprecated)) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, signatureToString(signature)); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 110ce8d7c0cd8..48549ab7c7f56 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4592,7 +4592,7 @@ namespace ts { /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments /* @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol - /* @internal */ allSignatureDeprecated?: boolean; // All signatures have the deprecated tag + /* @internal */ allSignaturesDeprecated?: boolean; // All signatures have the deprecated tag } /* @internal */ diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts new file mode 100644 index 0000000000000..ad4f95cf6ee19 --- /dev/null +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts @@ -0,0 +1,49 @@ +/// + +//// /** @deprecated */ +//// interface f { a: number } +//// declare function f(): void +//// declare const tf: f +//// f; +//// f(); + +//// interface b { a: number; } +//// /** @deprecated */ +//// declare function b(): void +//// declare const tb: b; +//// b +//// [|b()|]; + +//// interface c { } +//// /** @deprecated */ +//// declare function c(): void +//// declare function c(a: number): void +//// declare const tc: c; +//// c; +//// [|c()|]; +//// c(1); + +//// /** @deprecated */ +//// interface d { } +//// declare function d(): void +//// declare function d(a: number): void +//// declare const td: d; +//// d; +//// d(); +//// d(1); + +const ranges = test.ranges(); +verify.getSuggestionDiagnostics([ + { + message: "'(): void' is deprecated", + code: 6385, + range: ranges[0], + reportsDeprecated: true, + }, + { + message: "'(): void' is deprecated", + code: 6385, + range: ranges[1], + reportsDeprecated: true, + } +]) From d4365731a6cfbf09f81bd8b60cd007d6dec6bd16 Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Jun 2020 02:35:11 +0800 Subject: [PATCH 05/12] fix tests --- src/compiler/binder.ts | 24 ++++++++++-------- src/compiler/checker.ts | 25 +++++++++++-------- src/compiler/types.ts | 2 ++ src/compiler/utilities.ts | 9 +++++++ .../fourslash/jsdocDeprecated_suggestion3.ts | 18 ++++++++++--- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9fd1703ead56d..c1a21623a1d83 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -544,23 +544,27 @@ namespace ts { function checkDeprecatedForSymbol(node: Declaration, symbol: Symbol) { const hasDeprecated = !!(node.flags & NodeFlags.Deprecated); const isSignatureLike = !!(symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)); + if (hasDeprecated) { + symbol.flags |= SymbolFlags.Deprecated; + + if (symbol.flags & SymbolFlags.Type) { + symbol.typeDeprecated = true; + } + if (!isSignatureLike && symbol.flags & SymbolFlags.Value) { + symbol.valueDeprecated = true; + } + } + if (isSignatureLike) { - const hasSetDeprecated = symbol.allSignaturesDeprecated === undefined; - if (hasDeprecated && hasSetDeprecated) { + const hasSetDeprecated = symbol.allSignaturesDeprecated !== undefined; + if (hasDeprecated && !hasSetDeprecated) { const allSignaturesDeprecated = every(filter(symbol.declarations, isFunctionLike), decl => !!(decl.flags & NodeFlags.Deprecated)); symbol.allSignaturesDeprecated = allSignaturesDeprecated; - if (allSignaturesDeprecated) { - symbol.flags |= SymbolFlags.Deprecated; - } } - else if (!hasDeprecated && !hasSetDeprecated) { + else if (!hasDeprecated && hasSetDeprecated) { symbol.allSignaturesDeprecated = false; - symbol.flags &= ~SymbolFlags.Deprecated; } } - else if (hasDeprecated) { - symbol.flags |= SymbolFlags.Deprecated; - } } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6b92695cfd3fd..61a118ba1448d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13285,9 +13285,11 @@ namespace ts { if (propName !== undefined) { const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessNode && prop.flags & SymbolFlags.Deprecated) { - const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); - errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); + if (accessNode && (prop.flags & SymbolFlags.Deprecated)) { + if (isIndexedAccessTypeNode(accessNode) && prop.typeDeprecated || allSignatureOrValueDeprecatedForSymbol(prop)) { + const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); + errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); + } } if (accessExpression) { markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword); @@ -22007,10 +22009,11 @@ namespace ts { const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); let declaration: Declaration | undefined = localOrExportSymbol.valueDeclaration; - const target = (symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); - if (target.flags & SymbolFlags.Deprecated) { + const target = (localOrExportSymbol.flags & SymbolFlags.Alias ? resolveAlias(localOrExportSymbol) : localOrExportSymbol); + if (allSignatureOrValueDeprecatedForSymbol(target)) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, node.escapedText as string); } + if (localOrExportSymbol.flags & SymbolFlags.Class) { // Due to the emit for class decorators, any reference to the class from inside of the class body // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind @@ -24977,7 +24980,7 @@ namespace ts { propType = indexInfo.type; } else { - if (prop.flags & SymbolFlags.Deprecated) { + if (allSignatureOrValueDeprecatedForSymbol(prop)) { errorOrSuggestion(/* isError */ false, right, Diagnostics._0_is_deprecated, right.escapedText as string); } @@ -27368,10 +27371,10 @@ namespace ts { return nonInferrableType; } - if (signature.declaration && ( - (isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration)) || - !signature.declaration.symbol.allSignaturesDeprecated - ) && (signature.declaration.flags & NodeFlags.Deprecated)) { + if (signature.declaration && (signature.declaration.flags & NodeFlags.Deprecated) && ( + !signature.declaration.symbol.allSignaturesDeprecated || + isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration) + )) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, signatureToString(signature)); } @@ -30818,7 +30821,7 @@ namespace ts { } const symbol = getNodeLinks(node).resolvedSymbol; if (symbol) { - if (symbol.flags & SymbolFlags.Deprecated) { + if ((symbol.flags & SymbolFlags.Deprecated) && symbol.typeDeprecated) { const diagLocation = isTypeReferenceNode(node) && isQualifiedName(node.typeName) ? node.typeName.right : node; errorOrSuggestion(/* isError */ false, diagLocation, Diagnostics._0_is_deprecated, symbol.escapedName as string); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 48549ab7c7f56..dd88a69d33753 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4593,6 +4593,8 @@ namespace ts { /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments /* @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol /* @internal */ allSignaturesDeprecated?: boolean; // All signatures have the deprecated tag + /* @internal */ typeDeprecated?: boolean; + /* @internal */ valueDeprecated?: boolean; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e50dbd7224236..bf7a45f11791e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -918,6 +918,15 @@ namespace ts { } } + + export function allSignatureOrValueDeprecatedForSymbol(symbol: Symbol) { + const functionLikeFlags = SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method; + return symbol.flags & SymbolFlags.Deprecated && ( + (symbol.flags & functionLikeFlags) && symbol.allSignaturesDeprecated || + (symbol.flags & ~functionLikeFlags) && symbol.valueDeprecated + ); + } + export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3); diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts index ad4f95cf6ee19..b48721e07272e 100644 --- a/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts @@ -3,7 +3,7 @@ //// /** @deprecated */ //// interface f { a: number } //// declare function f(): void -//// declare const tf: f +//// declare const tf: [|f|] //// f; //// f(); @@ -27,7 +27,7 @@ //// interface d { } //// declare function d(): void //// declare function d(a: number): void -//// declare const td: d; +//// declare const td: [|d|]; //// d; //// d(); //// d(1); @@ -35,7 +35,7 @@ const ranges = test.ranges(); verify.getSuggestionDiagnostics([ { - message: "'(): void' is deprecated", + message: "'f' is deprecated", code: 6385, range: ranges[0], reportsDeprecated: true, @@ -45,5 +45,17 @@ verify.getSuggestionDiagnostics([ code: 6385, range: ranges[1], reportsDeprecated: true, + }, + { + message: "'(): void' is deprecated", + code: 6385, + range: ranges[2], + reportsDeprecated: true, + }, + { + message: "'d' is deprecated", + code: 6385, + range: ranges[3], + reportsDeprecated: true, } ]) From 756c27cfcd2468e3736e52ffd7486c642a653331 Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Jun 2020 19:18:18 +0800 Subject: [PATCH 06/12] refactor deprecate flags --- src/compiler/binder.ts | 27 +-------- src/compiler/checker.ts | 7 ++- src/compiler/types.ts | 12 +++- src/compiler/utilities.ts | 56 +++++++++++++++++-- .../fourslash/jsdocDeprecated_suggestion3.ts | 16 ++++-- 5 files changed, 77 insertions(+), 41 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c1a21623a1d83..ad35852c22865 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -537,34 +537,11 @@ namespace ts { symbol.parent = parent; } - checkDeprecatedForSymbol(node, symbol); - return symbol; - } - - function checkDeprecatedForSymbol(node: Declaration, symbol: Symbol) { - const hasDeprecated = !!(node.flags & NodeFlags.Deprecated); - const isSignatureLike = !!(symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)); - if (hasDeprecated) { + if (node.flags & NodeFlags.Deprecated) { symbol.flags |= SymbolFlags.Deprecated; - - if (symbol.flags & SymbolFlags.Type) { - symbol.typeDeprecated = true; - } - if (!isSignatureLike && symbol.flags & SymbolFlags.Value) { - symbol.valueDeprecated = true; - } } - if (isSignatureLike) { - const hasSetDeprecated = symbol.allSignaturesDeprecated !== undefined; - if (hasDeprecated && !hasSetDeprecated) { - const allSignaturesDeprecated = every(filter(symbol.declarations, isFunctionLike), decl => !!(decl.flags & NodeFlags.Deprecated)); - symbol.allSignaturesDeprecated = allSignaturesDeprecated; - } - else if (!hasDeprecated && hasSetDeprecated) { - symbol.allSignaturesDeprecated = false; - } - } + return symbol; } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 61a118ba1448d..b610ae32c9e7e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13286,7 +13286,8 @@ namespace ts { const prop = getPropertyOfType(objectType, propName); if (prop) { if (accessNode && (prop.flags & SymbolFlags.Deprecated)) { - if (isIndexedAccessTypeNode(accessNode) && prop.typeDeprecated || allSignatureOrValueDeprecatedForSymbol(prop)) { + const deprecatedFlags = getDeprecatedFlags(prop); + if (isIndexedAccessTypeNode(accessNode) && (deprecatedFlags & DeprecatedFlags.Type) || allSignatureOrValueDeprecatedForSymbol(prop)) { const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); } @@ -27372,7 +27373,7 @@ namespace ts { } if (signature.declaration && (signature.declaration.flags & NodeFlags.Deprecated) && ( - !signature.declaration.symbol.allSignaturesDeprecated || + !(getDeprecatedFlags(signature.declaration.symbol) & DeprecatedFlags.AllSignature) || isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration) )) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, signatureToString(signature)); @@ -30821,7 +30822,7 @@ namespace ts { } const symbol = getNodeLinks(node).resolvedSymbol; if (symbol) { - if ((symbol.flags & SymbolFlags.Deprecated) && symbol.typeDeprecated) { + if (getDeprecatedFlags(symbol) & DeprecatedFlags.Type) { const diagLocation = isTypeReferenceNode(node) && isQualifiedName(node.typeName) ? node.typeName.right : node; errorOrSuggestion(/* isError */ false, diagLocation, Diagnostics._0_is_deprecated, symbol.escapedName as string); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dd88a69d33753..555ae9c531f50 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4592,9 +4592,15 @@ namespace ts { /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments /* @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol - /* @internal */ allSignaturesDeprecated?: boolean; // All signatures have the deprecated tag - /* @internal */ typeDeprecated?: boolean; - /* @internal */ valueDeprecated?: boolean; + /* @internal */ deprecatedFlags?: DeprecatedFlags; + } + + export enum DeprecatedFlags { + None = 0, + Value = 1 << 0, + Type = 1 << 1, + Signature = 1 << 2, + AllSignature = 1 << 3 } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index bf7a45f11791e..8942d3ff058ba 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -918,13 +918,59 @@ namespace ts { } } + export function isTypeDeclaration(decl: Declaration): boolean { + switch (decl.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.TypeParameter: + return true; + default: + return false; + } + } + + export function getDeprecatedFlags(symbol: Symbol) { + if (symbol.flags & SymbolFlags.Deprecated) { + if (symbol.deprecatedFlags === undefined) { + let deprecatedFlags = DeprecatedFlags.None; + let allSignatureLikeDeprecated = true; + forEach(symbol.declarations, decl => { + const isTypeDecl = isTypeDeclaration(decl); + const hasDeprecated = decl.flags & NodeFlags.Deprecated; + if (hasDeprecated && symbol.flags & SymbolFlags.Type && isTypeDecl) { + deprecatedFlags |= DeprecatedFlags.Type; + } + + if ((symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) && isFunctionLike(decl)) { + if (hasDeprecated) { + deprecatedFlags |= DeprecatedFlags.Signature; + } + else { + allSignatureLikeDeprecated = false; + } + } + else if (hasDeprecated && symbol.flags & SymbolFlags.Value && !isTypeDecl) { + deprecatedFlags |= DeprecatedFlags.Value; + } + }); + + if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { + deprecatedFlags |= DeprecatedFlags.AllSignature; + } + + symbol.deprecatedFlags = deprecatedFlags; + } + return symbol.deprecatedFlags; + } + return DeprecatedFlags.None; + } export function allSignatureOrValueDeprecatedForSymbol(symbol: Symbol) { - const functionLikeFlags = SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method; - return symbol.flags & SymbolFlags.Deprecated && ( - (symbol.flags & functionLikeFlags) && symbol.allSignaturesDeprecated || - (symbol.flags & ~functionLikeFlags) && symbol.valueDeprecated - ); + const deprecatedFlags = getDeprecatedFlags(symbol); + return deprecatedFlags & (DeprecatedFlags.Value | DeprecatedFlags.AllSignature); } export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts index b48721e07272e..ccaa1cb341566 100644 --- a/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion3.ts @@ -11,8 +11,8 @@ //// /** @deprecated */ //// declare function b(): void //// declare const tb: b; -//// b -//// [|b()|]; +//// [|b|] +//// [|b|](); //// interface c { } //// /** @deprecated */ @@ -41,21 +41,27 @@ verify.getSuggestionDiagnostics([ reportsDeprecated: true, }, { - message: "'(): void' is deprecated", + message: "'b' is deprecated", code: 6385, range: ranges[1], reportsDeprecated: true, }, { - message: "'(): void' is deprecated", + message: "'b' is deprecated", code: 6385, range: ranges[2], reportsDeprecated: true, }, { - message: "'d' is deprecated", + message: "'(): void' is deprecated", code: 6385, range: ranges[3], reportsDeprecated: true, + }, + { + message: "'d' is deprecated", + code: 6385, + range: ranges[4], + reportsDeprecated: true, } ]) From fbb1f443168908991de54ca8369fc2c324f259ca Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Jun 2020 23:56:54 +0800 Subject: [PATCH 07/12] simplify code --- src/compiler/checker.ts | 15 +++++++-------- src/compiler/types.ts | 4 +++- src/compiler/utilities.ts | 10 +++------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1a4d67aec02b1..5d674147a6602 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13280,9 +13280,8 @@ namespace ts { if (propName !== undefined) { const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessNode && (prop.flags & SymbolFlags.Deprecated)) { - const deprecatedFlags = getDeprecatedFlags(prop); - if (isIndexedAccessTypeNode(accessNode) && (deprecatedFlags & DeprecatedFlags.Type) || allSignatureOrValueDeprecatedForSymbol(prop)) { + if (accessNode && prop.flags & SymbolFlags.Deprecated) { + if (getDeprecatedFlags(prop) & (DeprecatedFlags.Type | DeprecatedFlags.Value)) { const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); } @@ -22047,7 +22046,7 @@ namespace ts { let declaration: Declaration | undefined = localOrExportSymbol.valueDeclaration; const target = (localOrExportSymbol.flags & SymbolFlags.Alias ? resolveAlias(localOrExportSymbol) : localOrExportSymbol); - if (allSignatureOrValueDeprecatedForSymbol(target)) { + if (getDeprecatedFlags(target) & DeprecatedFlags.Value) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, node.escapedText as string); } @@ -25017,7 +25016,7 @@ namespace ts { propType = indexInfo.type; } else { - if (allSignatureOrValueDeprecatedForSymbol(prop)) { + if (getDeprecatedFlags(prop) & DeprecatedFlags.Value) { errorOrSuggestion(/* isError */ false, right, Diagnostics._0_is_deprecated, right.escapedText as string); } @@ -27408,8 +27407,8 @@ namespace ts { return nonInferrableType; } - if (signature.declaration && (signature.declaration.flags & NodeFlags.Deprecated) && ( - !(getDeprecatedFlags(signature.declaration.symbol) & DeprecatedFlags.AllSignature) || + if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated && ( + getDeprecatedFlags(signature.declaration.symbol) & DeprecatedFlags.Signature || isCallSignatureDeclaration(signature.declaration) || isConstructSignatureDeclaration(signature.declaration) )) { errorOrSuggestion(/* isError */ false, node, Diagnostics._0_is_deprecated, signatureToString(signature)); @@ -35203,7 +35202,7 @@ namespace ts { } } - if (isImportSpecifier(node) && target.flags & SymbolFlags.Deprecated) { + if (isImportSpecifier(node) && getDeprecatedFlags(target) & (DeprecatedFlags.Type | DeprecatedFlags.Value)) { errorOrSuggestion(/* isError */ false, node.name, Diagnostics._0_is_deprecated, symbol.escapedName as string); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d11a0d523ca9b..3416c1a33cb56 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4595,12 +4595,14 @@ namespace ts { /* @internal */ deprecatedFlags?: DeprecatedFlags; } + /* @internal */ export enum DeprecatedFlags { None = 0, Value = 1 << 0, Type = 1 << 1, Signature = 1 << 2, - AllSignature = 1 << 3 + + SignatureExcludes = Value | Type } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 59d2f5b6ed3a0..8bc5ecb43d472 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -938,7 +938,7 @@ namespace ts { deprecatedFlags |= DeprecatedFlags.Type; } - if ((symbol.flags & (SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) && isFunctionLike(decl)) { + if ((symbol.flags & (SymbolFlags.Constructor | SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) && isFunctionLike(decl)) { if (hasDeprecated) { deprecatedFlags |= DeprecatedFlags.Signature; } @@ -952,7 +952,8 @@ namespace ts { }); if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { - deprecatedFlags |= DeprecatedFlags.AllSignature; + deprecatedFlags &= DeprecatedFlags.SignatureExcludes; + deprecatedFlags |= DeprecatedFlags.Value; } symbol.deprecatedFlags = deprecatedFlags; @@ -962,11 +963,6 @@ namespace ts { return DeprecatedFlags.None; } - export function allSignatureOrValueDeprecatedForSymbol(symbol: Symbol) { - const deprecatedFlags = getDeprecatedFlags(symbol); - return deprecatedFlags & (DeprecatedFlags.Value | DeprecatedFlags.AllSignature); - } - export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3); From 2410ea6125f6ce1f5f9ea8c4a8720401887b50dc Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Jun 2020 23:57:15 +0800 Subject: [PATCH 08/12] revert smi helper --- src/compiler/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8bc5ecb43d472..2cf2b405d5701 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -952,7 +952,7 @@ namespace ts { }); if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { - deprecatedFlags &= DeprecatedFlags.SignatureExcludes; + deprecatedFlags &= ~DeprecatedFlags.Signature; deprecatedFlags |= DeprecatedFlags.Value; } From aab7a32e0ecc1397cac428be3f80e10476a5e648 Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Jun 2020 23:58:10 +0800 Subject: [PATCH 09/12] Add smi opt --- src/compiler/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2cf2b405d5701..8bc5ecb43d472 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -952,7 +952,7 @@ namespace ts { }); if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { - deprecatedFlags &= ~DeprecatedFlags.Signature; + deprecatedFlags &= DeprecatedFlags.SignatureExcludes; deprecatedFlags |= DeprecatedFlags.Value; } From d7a72972f838a855c68bd3a67d63fa435c0480e6 Mon Sep 17 00:00:00 2001 From: kingwl Date: Mon, 29 Jun 2020 17:04:13 +0800 Subject: [PATCH 10/12] Avoid check for union keys --- src/compiler/checker.ts | 6 +-- .../fourslash/jsdocDeprecated_suggestion4.ts | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d674147a6602..f5cb8699f8ba8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13274,13 +13274,13 @@ namespace ts { undefined; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { + function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags, reportDeprecated?: boolean) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessNode && prop.flags & SymbolFlags.Deprecated) { + if (reportDeprecated && accessNode && prop.flags & SymbolFlags.Deprecated) { if (getDeprecatedFlags(prop) & (DeprecatedFlags.Type | DeprecatedFlags.Value)) { const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); @@ -13652,7 +13652,7 @@ namespace ts { } return accessFlags & AccessFlags.Writing ? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments) : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol); + return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol, /* reportDeprecated */ true); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts new file mode 100644 index 0000000000000..9bcdf0de5e2b7 --- /dev/null +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts @@ -0,0 +1,50 @@ +/// + +//// interface Foo { +//// /** @deprecated */ +//// f: number +//// b: number +//// /** @deprecated */ +//// baz: number +//// } + +//// declare const f: Foo +//// f.[|f|]; +//// f.b; +//// f.[|baz|]; + +//// const kf = 'f' +//// const kb = 'b' +//// declare const k: 'f' | 'b' | 'baz' +//// declare const kfb: 'f' | 'b' +//// declare const kfz: 'f' | 'baz' +//// declare const keys: keyof Foo +//// f[[|kf|]] +//// f[kb] +//// f[k] +//// f[kfb] +//// f[kfz] +//// f[keys] + + +const ranges = test.ranges(); +verify.getSuggestionDiagnostics([ + { + message: "'f' is deprecated", + code: 6385, + range: ranges[0], + reportsDeprecated: true, + }, + { + message: "'baz' is deprecated", + code: 6385, + range: ranges[1], + reportsDeprecated: true, + }, + { + message: "'f' is deprecated", + code: 6385, + range: ranges[2], + reportsDeprecated: true, + } +]) From 11340daa03ce329c5dd6fca5d10456ce6a87c7ed Mon Sep 17 00:00:00 2001 From: kingwl Date: Mon, 29 Jun 2020 17:23:32 +0800 Subject: [PATCH 11/12] Revert "Avoid check for union keys" This reverts commit d7a72972f838a855c68bd3a67d63fa435c0480e6. --- src/compiler/checker.ts | 6 +-- .../fourslash/jsdocDeprecated_suggestion4.ts | 50 ------------------- 2 files changed, 3 insertions(+), 53 deletions(-) delete mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f5cb8699f8ba8..5d674147a6602 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13274,13 +13274,13 @@ namespace ts { undefined; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags, reportDeprecated?: boolean) { + function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { const prop = getPropertyOfType(objectType, propName); if (prop) { - if (reportDeprecated && accessNode && prop.flags & SymbolFlags.Deprecated) { + if (accessNode && prop.flags & SymbolFlags.Deprecated) { if (getDeprecatedFlags(prop) & (DeprecatedFlags.Type | DeprecatedFlags.Value)) { const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); errorOrSuggestion(/* isError */ false, deprecatedNode, Diagnostics._0_is_deprecated, propName as string); @@ -13652,7 +13652,7 @@ namespace ts { } return accessFlags & AccessFlags.Writing ? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments) : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol, /* reportDeprecated */ true); + return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts deleted file mode 100644 index 9bcdf0de5e2b7..0000000000000 --- a/tests/cases/fourslash/jsdocDeprecated_suggestion4.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// - -//// interface Foo { -//// /** @deprecated */ -//// f: number -//// b: number -//// /** @deprecated */ -//// baz: number -//// } - -//// declare const f: Foo -//// f.[|f|]; -//// f.b; -//// f.[|baz|]; - -//// const kf = 'f' -//// const kb = 'b' -//// declare const k: 'f' | 'b' | 'baz' -//// declare const kfb: 'f' | 'b' -//// declare const kfz: 'f' | 'baz' -//// declare const keys: keyof Foo -//// f[[|kf|]] -//// f[kb] -//// f[k] -//// f[kfb] -//// f[kfz] -//// f[keys] - - -const ranges = test.ranges(); -verify.getSuggestionDiagnostics([ - { - message: "'f' is deprecated", - code: 6385, - range: ranges[0], - reportsDeprecated: true, - }, - { - message: "'baz' is deprecated", - code: 6385, - range: ranges[1], - reportsDeprecated: true, - }, - { - message: "'f' is deprecated", - code: 6385, - range: ranges[2], - reportsDeprecated: true, - } -]) From 2dd4148ab36516a1544f4d33da28d16daf615626 Mon Sep 17 00:00:00 2001 From: kingwl Date: Tue, 30 Jun 2020 23:44:12 +0800 Subject: [PATCH 12/12] use symbol links --- src/compiler/checker.ts | 39 +++++++++++++++++++++++++++++++++++++++ src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 37 ------------------------------------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d674147a6602..7b8c4fdc5ba11 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13274,6 +13274,45 @@ namespace ts { undefined; } + function getDeprecatedFlags(symbol: Symbol) { + if (!(symbol.flags & SymbolFlags.Deprecated)) { + return DeprecatedFlags.None; + } + + const symbolLinks = getSymbolLinks(symbol); + if (symbolLinks.deprecatedFlags === undefined) { + let deprecatedFlags = DeprecatedFlags.None; + let allSignatureLikeDeprecated = true; + forEach(symbol.declarations, decl => { + const isTypeDecl = isTypeDeclaration(decl); + const hasDeprecated = decl.flags & NodeFlags.Deprecated; + if (hasDeprecated && symbol.flags & SymbolFlags.Type && isTypeDecl) { + deprecatedFlags |= DeprecatedFlags.Type; + } + + if ((symbol.flags & (SymbolFlags.Constructor | SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) && isFunctionLike(decl)) { + if (hasDeprecated) { + deprecatedFlags |= DeprecatedFlags.Signature; + } + else { + allSignatureLikeDeprecated = false; + } + } + else if (hasDeprecated && symbol.flags & SymbolFlags.Value && !isTypeDecl) { + deprecatedFlags |= DeprecatedFlags.Value; + } + }); + + if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { + deprecatedFlags &= DeprecatedFlags.SignatureExcludes; + deprecatedFlags |= DeprecatedFlags.Value; + } + + symbolLinks.deprecatedFlags = deprecatedFlags; + } + return symbolLinks.deprecatedFlags; + } + function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3416c1a33cb56..169e69fe15c8b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4592,7 +4592,6 @@ namespace ts { /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments /* @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol - /* @internal */ deprecatedFlags?: DeprecatedFlags; } /* @internal */ @@ -4645,6 +4644,7 @@ namespace ts { typeOnlyDeclaration?: TypeOnlyCompatibleAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label + deprecatedFlags?: DeprecatedFlags; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8bc5ecb43d472..294fbb2998e53 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -926,43 +926,6 @@ namespace ts { } } - export function getDeprecatedFlags(symbol: Symbol) { - if (symbol.flags & SymbolFlags.Deprecated) { - if (symbol.deprecatedFlags === undefined) { - let deprecatedFlags = DeprecatedFlags.None; - let allSignatureLikeDeprecated = true; - forEach(symbol.declarations, decl => { - const isTypeDecl = isTypeDeclaration(decl); - const hasDeprecated = decl.flags & NodeFlags.Deprecated; - if (hasDeprecated && symbol.flags & SymbolFlags.Type && isTypeDecl) { - deprecatedFlags |= DeprecatedFlags.Type; - } - - if ((symbol.flags & (SymbolFlags.Constructor | SymbolFlags.Signature | SymbolFlags.Function | SymbolFlags.Method)) && isFunctionLike(decl)) { - if (hasDeprecated) { - deprecatedFlags |= DeprecatedFlags.Signature; - } - else { - allSignatureLikeDeprecated = false; - } - } - else if (hasDeprecated && symbol.flags & SymbolFlags.Value && !isTypeDecl) { - deprecatedFlags |= DeprecatedFlags.Value; - } - }); - - if (deprecatedFlags & DeprecatedFlags.Signature && allSignatureLikeDeprecated) { - deprecatedFlags &= DeprecatedFlags.SignatureExcludes; - deprecatedFlags |= DeprecatedFlags.Value; - } - - symbol.deprecatedFlags = deprecatedFlags; - } - return symbol.deprecatedFlags; - } - return DeprecatedFlags.None; - } - export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3);