From 3c43b6b1be864871e7696c65980479fb8dc0e9ab Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 27 Apr 2023 19:45:10 +0300 Subject: [PATCH] fix(53754): Re-exported symbol marked with deprecated doesn't get correct deprecation highlighting (#53808) --- src/compiler/checker.ts | 38 ++++++++++--------- .../fourslash/jsdocDeprecated_suggestion20.ts | 37 ++++++++++++++++++ .../fourslash/jsdocDeprecated_suggestion21.ts | 31 +++++++++++++++ 3 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion20.ts create mode 100644 tests/cases/fourslash/jsdocDeprecated_suggestion21.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 869edfaffd4..1266af41840 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2392,13 +2392,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isDeprecatedSymbol(symbol: Symbol) { - if (length(symbol.declarations) > 1) { - const parentSymbol = getParentOfSymbol(symbol); - if (parentSymbol && parentSymbol.flags & SymbolFlags.Interface) { - return some(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); - } + const parentSymbol = getParentOfSymbol(symbol); + if (parentSymbol && length(symbol.declarations) > 1) { + return parentSymbol.flags & SymbolFlags.Interface ? some(symbol.declarations, isDeprecatedDeclaration) : every(symbol.declarations, isDeprecatedDeclaration); } - return !!(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Deprecated); + return !!symbol.valueDeclaration && isDeprecatedDeclaration(symbol.valueDeclaration) + || length(symbol.declarations) && every(symbol.declarations, isDeprecatedDeclaration); + } + + function isDeprecatedDeclaration(declaration: Declaration) { + return !!(getCombinedNodeFlags(declaration) & NodeFlags.Deprecated); } function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) { @@ -27886,7 +27889,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - const targetSymbol = checkDeprecatedAliasedSymbol(localOrExportSymbol, node); + const targetSymbol = resolveAliasWithDeprecationCheck(localOrExportSymbol, node); if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); } @@ -31550,8 +31553,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - if (isDeprecatedSymbol(prop) && isUncalledFunctionReference(node, prop) && prop.declarations) { - addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string); + const targetPropSymbol = resolveAliasWithDeprecationCheck(prop, right); + if (isDeprecatedSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) && targetPropSymbol.declarations) { + addDeprecatedSuggestion(right, targetPropSymbol.declarations, right.escapedText as string); } checkPropertyNotUsedBeforeDeclaration(prop, node, right); markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol)); @@ -44164,20 +44168,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isImportSpecifier(node)) { - const targetSymbol = checkDeprecatedAliasedSymbol(symbol, node); - if (isDeprecatedAliasedSymbol(targetSymbol) && targetSymbol.declarations) { + const targetSymbol = resolveAliasWithDeprecationCheck(symbol, node); + if (isDeprecatedSymbol(targetSymbol) && targetSymbol.declarations) { addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string); } } } } - function isDeprecatedAliasedSymbol(symbol: Symbol) { - return !!symbol.declarations && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); - } - - function checkDeprecatedAliasedSymbol(symbol: Symbol, location: Node) { - if (!(symbol.flags & SymbolFlags.Alias)) return symbol; + function resolveAliasWithDeprecationCheck(symbol: Symbol, location: Node) { + if (!(symbol.flags & SymbolFlags.Alias) || isDeprecatedSymbol(symbol) || !getDeclarationOfAliasSymbol(symbol)) { + return symbol; + } const targetSymbol = resolveAlias(symbol); if (targetSymbol === unknownSymbol) return targetSymbol; @@ -44187,7 +44189,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target) { if (target === targetSymbol) break; if (target.declarations && length(target.declarations)) { - if (isDeprecatedAliasedSymbol(target)) { + if (isDeprecatedSymbol(target)) { addDeprecatedSuggestion(location, target.declarations, target.escapedName as string); break; } diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion20.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion20.ts new file mode 100644 index 00000000000..46c190db289 --- /dev/null +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion20.ts @@ -0,0 +1,37 @@ +/// + +// @module: esnext +// @filename: /a.ts +////export default function a() {} + +// @filename: /b.ts +////import _a from "./a"; +////export { +//// /** @deprecated a is deprecated */ +//// _a as a, +////}; +/////** @deprecated b is deprecated */ +////export const b = (): void => {}; + +// @filename: /c.ts +////import * as _ from "./b"; +//// +////_.[|a|]() +////_.[|b|]() + +goTo.file("/c.ts") +verify.getSuggestionDiagnostics([ + { + "code": 6385, + "message": "'a' is deprecated.", + "reportsDeprecated": true, + "range": test.ranges()[0] + }, + { + "code": 6385, + "message": "'b' is deprecated.", + "reportsDeprecated": true, + "range": test.ranges()[1] + }, +]); + diff --git a/tests/cases/fourslash/jsdocDeprecated_suggestion21.ts b/tests/cases/fourslash/jsdocDeprecated_suggestion21.ts new file mode 100644 index 00000000000..4fdc2bc69f7 --- /dev/null +++ b/tests/cases/fourslash/jsdocDeprecated_suggestion21.ts @@ -0,0 +1,31 @@ +/// + +// @module: esnext +// @filename: /a.ts +////export const a = 1; +////export const b = 1; + +// @filename: /b.ts +////export { +//// /** @deprecated a is deprecated */ +//// a +////} from "./a"; + +// @filename: /c.ts +////export { +//// a +////} from "./b"; + +// @filename: /d.ts +////import * as _ from "./c"; +////_.[|a|] + +goTo.file("/d.ts") +verify.getSuggestionDiagnostics([ + { + "code": 6385, + "message": "'a' is deprecated.", + "reportsDeprecated": true, + "range": test.ranges()[0] + }, +]);