Skip to content

Commit 20b5523

Browse files
authored
feat(42684): allow deprecated JSDoc tag to be used on aliased nodes (#47293)
1 parent 0673f02 commit 20b5523

File tree

9 files changed

+154
-14
lines changed

9 files changed

+154
-14
lines changed

src/compiler/checker.ts

+46-7
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,10 @@ namespace ts {
11981198
return diagnostic;
11991199
}
12001200

1201+
function isDeprecatedSymbol(symbol: Symbol) {
1202+
return !!(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Deprecated);
1203+
}
1204+
12011205
function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) {
12021206
const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_deprecated, deprecatedEntity);
12031207
return addDeprecatedSuggestionWorker(declarations, diagnostic);
@@ -15184,7 +15188,7 @@ namespace ts {
1518415188
}
1518515189
const prop = getPropertyOfType(objectType, propName);
1518615190
if (prop) {
15187-
if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(accessNode, prop)) {
15191+
if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) {
1518815192
const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode);
1518915193
addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string);
1519015194
}
@@ -25143,9 +25147,9 @@ namespace ts {
2514325147
}
2514425148

2514525149
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
25146-
const sourceSymbol = localOrExportSymbol.flags & SymbolFlags.Alias ? resolveAlias(localOrExportSymbol) : localOrExportSymbol;
25147-
if (sourceSymbol.declarations && getDeclarationNodeFlagsFromSymbol(sourceSymbol) & NodeFlags.Deprecated && isUncalledFunctionReference(node, sourceSymbol)) {
25148-
addDeprecatedSuggestion(node, sourceSymbol.declarations, node.escapedText as string);
25150+
const targetSymbol = checkDeprecatedAliasedSymbol(localOrExportSymbol, node);
25151+
if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) {
25152+
addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string);
2514925153
}
2515025154

2515125155
let declaration = localOrExportSymbol.valueDeclaration;
@@ -28512,7 +28516,7 @@ namespace ts {
2851228516
}
2851328517
}
2851428518
else {
28515-
if (prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(node, prop)) {
28519+
if (isDeprecatedSymbol(prop) && isUncalledFunctionReference(node, prop) && prop.declarations) {
2851628520
addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string);
2851728521
}
2851828522
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
@@ -39889,10 +39893,45 @@ namespace ts {
3988939893
}
3989039894
}
3989139895

39892-
if (isImportSpecifier(node) && target.declarations?.every(d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated))) {
39893-
addDeprecatedSuggestion(node.name, target.declarations, symbol.escapedName as string);
39896+
if (isImportSpecifier(node)) {
39897+
const targetSymbol = checkDeprecatedAliasedSymbol(symbol, node);
39898+
if (isDeprecatedAliasedSymbol(targetSymbol) && targetSymbol.declarations) {
39899+
addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string);
39900+
}
39901+
}
39902+
}
39903+
}
39904+
39905+
function isDeprecatedAliasedSymbol(symbol: Symbol) {
39906+
return !!symbol.declarations && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated));
39907+
}
39908+
39909+
function checkDeprecatedAliasedSymbol(symbol: Symbol, location: Node) {
39910+
if (!(symbol.flags & SymbolFlags.Alias)) return symbol;
39911+
39912+
const targetSymbol = resolveAlias(symbol);
39913+
if (targetSymbol === unknownSymbol) return targetSymbol;
39914+
39915+
while (symbol.flags & SymbolFlags.Alias) {
39916+
const target = getImmediateAliasedSymbol(symbol);
39917+
if (target) {
39918+
if (target === targetSymbol) break;
39919+
if (target.declarations && length(target.declarations)) {
39920+
if (isDeprecatedAliasedSymbol(target)) {
39921+
addDeprecatedSuggestion(location, target.declarations, target.escapedName as string);
39922+
break;
39923+
}
39924+
else {
39925+
if (symbol === targetSymbol) break;
39926+
symbol = target;
39927+
}
39928+
}
39929+
}
39930+
else {
39931+
break;
3989439932
}
3989539933
}
39934+
return targetSymbol;
3989639935
}
3989739936

3989839937
function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) {

src/compiler/parser.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -7406,7 +7406,8 @@ namespace ts {
74067406
}
74077407

74087408
function parseExportSpecifier() {
7409-
return parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier;
7409+
const hasJSDoc = hasPrecedingJSDocComment();
7410+
return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc);
74107411
}
74117412

74127413
function parseImportSpecifier() {

src/compiler/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ namespace ts {
929929
| JSDocFunctionType
930930
| ExportDeclaration
931931
| NamedTupleMember
932+
| ExportSpecifier
932933
| EndOfFileToken
933934
;
934935

@@ -3117,7 +3118,7 @@ namespace ts {
31173118
readonly isTypeOnly: boolean;
31183119
}
31193120

3120-
export interface ExportSpecifier extends NamedDeclaration {
3121+
export interface ExportSpecifier extends NamedDeclaration, JSDocContainer {
31213122
readonly kind: SyntaxKind.ExportSpecifier;
31223123
readonly parent: NamedExports;
31233124
readonly isTypeOnly: boolean;

src/compiler/utilities.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1247,7 +1247,8 @@ namespace ts {
12471247
node.kind === SyntaxKind.FunctionExpression ||
12481248
node.kind === SyntaxKind.ArrowFunction ||
12491249
node.kind === SyntaxKind.ParenthesizedExpression ||
1250-
node.kind === SyntaxKind.VariableDeclaration) ?
1250+
node.kind === SyntaxKind.VariableDeclaration ||
1251+
node.kind === SyntaxKind.ExportSpecifier) ?
12511252
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
12521253
getLeadingCommentRanges(text, node.pos);
12531254
// True if the comment starts with '/**' but not if it is '/**/'

tests/baselines/reference/api/tsserverlibrary.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ declare namespace ts {
572572
}
573573
export interface JSDocContainer {
574574
}
575-
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ClassStaticBlockDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | EmptyStatement | DebuggerStatement | Block | VariableStatement | ExpressionStatement | IfStatement | DoStatement | WhileStatement | ForStatement | ForInStatement | ForOfStatement | BreakStatement | ContinueStatement | ReturnStatement | WithStatement | SwitchStatement | LabeledStatement | ThrowStatement | TryStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
575+
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ClassStaticBlockDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | EmptyStatement | DebuggerStatement | Block | VariableStatement | ExpressionStatement | IfStatement | DoStatement | WhileStatement | ForStatement | ForInStatement | ForOfStatement | BreakStatement | ContinueStatement | ReturnStatement | WithStatement | SwitchStatement | LabeledStatement | ThrowStatement | TryStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | ExportSpecifier | EndOfFileToken;
576576
export type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
577577
export type HasTypeArguments = CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement | JsxSelfClosingElement;
578578
export type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
@@ -1702,7 +1702,7 @@ declare namespace ts {
17021702
readonly name: Identifier;
17031703
readonly isTypeOnly: boolean;
17041704
}
1705-
export interface ExportSpecifier extends NamedDeclaration {
1705+
export interface ExportSpecifier extends NamedDeclaration, JSDocContainer {
17061706
readonly kind: SyntaxKind.ExportSpecifier;
17071707
readonly parent: NamedExports;
17081708
readonly isTypeOnly: boolean;

tests/baselines/reference/api/typescript.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ declare namespace ts {
572572
}
573573
export interface JSDocContainer {
574574
}
575-
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ClassStaticBlockDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | EmptyStatement | DebuggerStatement | Block | VariableStatement | ExpressionStatement | IfStatement | DoStatement | WhileStatement | ForStatement | ForInStatement | ForOfStatement | BreakStatement | ContinueStatement | ReturnStatement | WithStatement | SwitchStatement | LabeledStatement | ThrowStatement | TryStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
575+
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ClassStaticBlockDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | EmptyStatement | DebuggerStatement | Block | VariableStatement | ExpressionStatement | IfStatement | DoStatement | WhileStatement | ForStatement | ForInStatement | ForOfStatement | BreakStatement | ContinueStatement | ReturnStatement | WithStatement | SwitchStatement | LabeledStatement | ThrowStatement | TryStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | ExportSpecifier | EndOfFileToken;
576576
export type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
577577
export type HasTypeArguments = CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement | JsxSelfClosingElement;
578578
export type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
@@ -1702,7 +1702,7 @@ declare namespace ts {
17021702
readonly name: Identifier;
17031703
readonly isTypeOnly: boolean;
17041704
}
1705-
export interface ExportSpecifier extends NamedDeclaration {
1705+
export interface ExportSpecifier extends NamedDeclaration, JSDocContainer {
17061706
readonly kind: SyntaxKind.ExportSpecifier;
17071707
readonly parent: NamedExports;
17081708
readonly isTypeOnly: boolean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////export const a = 1;
6+
////export const b = 1;
7+
8+
// @filename: /b.ts
9+
////export {
10+
//// /** @deprecated a is deprecated */
11+
//// a
12+
////} from "./a";
13+
14+
// @filename: /c.ts
15+
////import { [|a|] } from "./b";
16+
////[|a|]
17+
18+
goTo.file("/c.ts")
19+
20+
verify.getSuggestionDiagnostics([
21+
{
22+
"code": 6385,
23+
"message": "'a' is deprecated.",
24+
"reportsDeprecated": true,
25+
"range": test.ranges()[0]
26+
},
27+
{
28+
"code": 6385,
29+
"message": "'a' is deprecated.",
30+
"reportsDeprecated": true,
31+
"range": test.ranges()[1]
32+
},
33+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////export const a = 1;
6+
////export const b = 1;
7+
8+
// @filename: /b.ts
9+
////export {
10+
//// /** @deprecated a is deprecated */
11+
//// a
12+
////} from "./a";
13+
14+
// @filename: /c.ts
15+
////export {
16+
//// a
17+
////} from "./b";
18+
19+
// @filename: /d.ts
20+
////import { [|a|] } from "./c";
21+
////[|a|]
22+
23+
goTo.file("/d.ts")
24+
25+
verify.getSuggestionDiagnostics([
26+
{
27+
"code": 6385,
28+
"message": "'a' is deprecated.",
29+
"reportsDeprecated": true,
30+
"range": test.ranges()[0]
31+
},
32+
{
33+
"code": 6385,
34+
"message": "'a' is deprecated.",
35+
"reportsDeprecated": true,
36+
"range": test.ranges()[1]
37+
},
38+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////const a = 1;
6+
////const b = 1;
7+
////export { a, /** @deprecated b is deprecated */ b }
8+
9+
// @filename: /b.ts
10+
////import { [|b|] } from "./a";
11+
////[|b|]
12+
13+
goTo.file("/b.ts")
14+
verify.getSuggestionDiagnostics([
15+
{
16+
"code": 6385,
17+
"message": "'b' is deprecated.",
18+
"reportsDeprecated": true,
19+
"range": test.ranges()[0]
20+
},
21+
{
22+
"code": 6385,
23+
"message": "'b' is deprecated.",
24+
"reportsDeprecated": true,
25+
"range": test.ranges()[1]
26+
},
27+
]);

0 commit comments

Comments
 (0)