Skip to content

Commit 2729e01

Browse files
committed
feat(42684): allow deprecated JSDoc tag to be used on aliased nodes
1 parent ef9fd97 commit 2729e01

File tree

9 files changed

+154
-14
lines changed

9 files changed

+154
-14
lines changed

src/compiler/checker.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,10 @@ namespace ts {
11941194
return diagnostic;
11951195
}
11961196

1197+
function isDeprecatedSymbol(symbol: Symbol) {
1198+
return !!(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Deprecated);
1199+
}
1200+
11971201
function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) {
11981202
const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_deprecated, deprecatedEntity);
11991203
return addDeprecatedSuggestionWorker(declarations, diagnostic);
@@ -15175,7 +15179,7 @@ namespace ts {
1517515179
}
1517615180
const prop = getPropertyOfType(objectType, propName);
1517715181
if (prop) {
15178-
if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(accessNode, prop)) {
15182+
if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) {
1517915183
const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode);
1518015184
addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string);
1518115185
}
@@ -25066,9 +25070,9 @@ namespace ts {
2506625070
}
2506725071

2506825072
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
25069-
const sourceSymbol = localOrExportSymbol.flags & SymbolFlags.Alias ? resolveAlias(localOrExportSymbol) : localOrExportSymbol;
25070-
if (sourceSymbol.declarations && getDeclarationNodeFlagsFromSymbol(sourceSymbol) & NodeFlags.Deprecated && isUncalledFunctionReference(node, sourceSymbol)) {
25071-
addDeprecatedSuggestion(node, sourceSymbol.declarations, node.escapedText as string);
25073+
const targetSymbol = checkDeprecatedAliasedSymbol(localOrExportSymbol, node);
25074+
if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) {
25075+
addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string);
2507225076
}
2507325077

2507425078
let declaration = localOrExportSymbol.valueDeclaration;
@@ -28460,7 +28464,7 @@ namespace ts {
2846028464
}
2846128465
}
2846228466
else {
28463-
if (prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(node, prop)) {
28467+
if (isDeprecatedSymbol(prop) && isUncalledFunctionReference(node, prop) && prop.declarations) {
2846428468
addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string);
2846528469
}
2846628470
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
@@ -39802,10 +39806,45 @@ namespace ts {
3980239806
}
3980339807
}
3980439808

39805-
if (isImportSpecifier(node) && target.declarations?.every(d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated))) {
39806-
addDeprecatedSuggestion(node.name, target.declarations, symbol.escapedName as string);
39809+
if (isImportSpecifier(node)) {
39810+
const targetSymbol = checkDeprecatedAliasedSymbol(symbol, node);
39811+
if (isDeprecatedAliasedSymbol(targetSymbol) && targetSymbol.declarations) {
39812+
addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string);
39813+
}
39814+
}
39815+
}
39816+
}
39817+
39818+
function isDeprecatedAliasedSymbol(symbol: Symbol) {
39819+
return !!symbol.declarations && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated));
39820+
}
39821+
39822+
function checkDeprecatedAliasedSymbol(symbol: Symbol, location: Node) {
39823+
if (!(symbol.flags & SymbolFlags.Alias)) return symbol;
39824+
39825+
const targetSymbol = resolveAlias(symbol);
39826+
if (targetSymbol === unknownSymbol) return targetSymbol;
39827+
39828+
while (symbol.flags & SymbolFlags.Alias) {
39829+
const target = getImmediateAliasedSymbol(symbol);
39830+
if (target) {
39831+
if (target === targetSymbol) break;
39832+
if (target.declarations && length(target.declarations)) {
39833+
if (isDeprecatedAliasedSymbol(target)) {
39834+
addDeprecatedSuggestion(location, target.declarations, target.escapedName as string);
39835+
break;
39836+
}
39837+
else {
39838+
if (symbol === targetSymbol) break;
39839+
symbol = target;
39840+
}
39841+
}
39842+
}
39843+
else {
39844+
break;
3980739845
}
3980839846
}
39847+
return targetSymbol;
3980939848
}
3981039849

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

src/compiler/parser.ts

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,8 @@ namespace ts {
12431243
node.kind === SyntaxKind.FunctionExpression ||
12441244
node.kind === SyntaxKind.ArrowFunction ||
12451245
node.kind === SyntaxKind.ParenthesizedExpression ||
1246-
node.kind === SyntaxKind.VariableDeclaration) ?
1246+
node.kind === SyntaxKind.VariableDeclaration ||
1247+
node.kind === SyntaxKind.ExportSpecifier) ?
12471248
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
12481249
getLeadingCommentRanges(text, node.pos);
12491250
// True if the comment starts with '/**' but not if it is '/**/'

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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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;
Lines changed: 33 additions & 0 deletions
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+
]);
Lines changed: 38 additions & 0 deletions
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+
]);
Lines changed: 27 additions & 0 deletions
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)