Skip to content

Commit 3cd9f3d

Browse files
author
Andy
authored
Support services for @typedef (#16087)
* Support services for @typedef * Ensure JSDocTypeReference has SemanticMeaning.Type * Get SemanticMeaning right
1 parent 6972766 commit 3cd9f3d

File tree

8 files changed

+97
-11
lines changed

8 files changed

+97
-11
lines changed

src/compiler/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,6 +2102,7 @@ namespace ts {
21022102
}
21032103

21042104
export interface JSDocTag extends Node {
2105+
parent: JSDoc;
21052106
atToken: AtToken;
21062107
tagName: Identifier;
21072108
comment: string | undefined;
@@ -2132,6 +2133,7 @@ namespace ts {
21322133
}
21332134

21342135
export interface JSDocTypedefTag extends JSDocTag, NamedDeclaration {
2136+
parent: JSDoc;
21352137
kind: SyntaxKind.JSDocTypedefTag;
21362138
fullName?: JSDocNamespaceDeclaration | Identifier;
21372139
name?: Identifier;
@@ -2140,6 +2142,7 @@ namespace ts {
21402142
}
21412143

21422144
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
2145+
parent: JSDoc;
21432146
kind: SyntaxKind.JSDocPropertyTag;
21442147
name: Identifier;
21452148
typeExpression: JSDocTypeExpression;

src/compiler/utilities.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ namespace ts {
288288
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
289289
}
290290

291+
export function isJSDoc(node: Node): node is JSDoc {
292+
return node.kind === SyntaxKind.JSDocComment;
293+
}
294+
295+
export function isJSDocTypedefTag(node: Node): node is JSDocTypedefTag {
296+
return node.kind === SyntaxKind.JSDocTypedefTag;
297+
}
298+
291299
export function isJSDocTag(node: Node) {
292300
return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
293301
}
@@ -1551,6 +1559,10 @@ namespace ts {
15511559
}
15521560

15531561
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
1562+
if (isJSDocTypedefTag(node)) {
1563+
return [node.parent];
1564+
}
1565+
15541566
let cache: (JSDoc | JSDocTag)[] = node.jsDocCache;
15551567
if (!cache) {
15561568
getJSDocsWorker(node);

src/services/findAllReferences.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,8 @@ namespace ts.FindAllReferences.Core {
784784
return;
785785
}
786786

787-
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, /*fullStart*/ state.options.findInComments || container.jsDoc !== undefined)) {
787+
const fullStart = state.options.findInComments || container.jsDoc !== undefined || forEach(search.symbol.declarations, d => d.kind === ts.SyntaxKind.JSDocTypedefTag);
788+
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, fullStart)) {
788789
getReferencesAtLocation(sourceFile, position, search, state);
789790
}
790791
}

src/services/goToDefinition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ts.GoToDefinition {
88
if (referenceFile) {
99
return [getDefinitionInfoForFileReference(comment.fileName, referenceFile.fileName)];
1010
}
11-
return undefined;
11+
// Might still be on jsdoc, so keep looking.
1212
}
1313

1414
// Type reference directives

src/services/utilities.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ namespace ts {
3939
case SyntaxKind.TypeLiteral:
4040
return SemanticMeaning.Type;
4141

42+
case SyntaxKind.JSDocTypedefTag:
43+
// If it has no name node, it shares the name with the value declaration below it.
44+
return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type : SemanticMeaning.Type;
45+
4246
case SyntaxKind.EnumMember:
4347
case SyntaxKind.ClassDeclaration:
4448
return SemanticMeaning.Value | SemanticMeaning.Type;
4549

46-
case SyntaxKind.EnumDeclaration:
47-
return SemanticMeaning.All;
48-
4950
case SyntaxKind.ModuleDeclaration:
5051
if (isAmbientModule(<ModuleDeclaration>node)) {
5152
return SemanticMeaning.Namespace | SemanticMeaning.Value;
@@ -57,6 +58,7 @@ namespace ts {
5758
return SemanticMeaning.Namespace;
5859
}
5960

61+
case SyntaxKind.EnumDeclaration:
6062
case SyntaxKind.NamedImports:
6163
case SyntaxKind.ImportSpecifier:
6264
case SyntaxKind.ImportEqualsDeclaration:
@@ -70,15 +72,15 @@ namespace ts {
7072
return SemanticMeaning.Namespace | SemanticMeaning.Value;
7173
}
7274

73-
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
75+
return SemanticMeaning.All;
7476
}
7577

7678
export function getMeaningFromLocation(node: Node): SemanticMeaning {
7779
if (node.kind === SyntaxKind.SourceFile) {
7880
return SemanticMeaning.Value;
7981
}
8082
else if (node.parent.kind === SyntaxKind.ExportAssignment) {
81-
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
83+
return SemanticMeaning.All;
8284
}
8385
else if (isInRightSideOfImport(node)) {
8486
return getMeaningFromRightHandSideOfImportEquals(node);
@@ -162,10 +164,22 @@ namespace ts {
162164
node = node.parent;
163165
}
164166

165-
return node.parent.kind === SyntaxKind.TypeReference ||
166-
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent)) ||
167-
(node.kind === SyntaxKind.ThisKeyword && !isPartOfExpression(node)) ||
168-
node.kind === SyntaxKind.ThisType;
167+
switch (node.kind) {
168+
case SyntaxKind.ThisKeyword:
169+
return !isPartOfExpression(node);
170+
case SyntaxKind.ThisType:
171+
return true;
172+
}
173+
174+
switch (node.parent.kind) {
175+
case SyntaxKind.TypeReference:
176+
case SyntaxKind.JSDocTypeReference:
177+
return true;
178+
case SyntaxKind.ExpressionWithTypeArguments:
179+
return !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent);
180+
}
181+
182+
return false;
169183
}
170184

171185
export function isCallExpressionTarget(node: Node): boolean {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
///<reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
// @Filename: a.js
5+
6+
/////** @typedef {number} [|{| "isWriteAccess": true, "isDefinition": true |}T|] */
7+
8+
////const [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 1;
9+
10+
/////** @type {[|T|]} */
11+
////const n = [|T|];
12+
13+
const [t0, v0, t1, v1] = test.ranges();
14+
15+
verify.singleReferenceGroup("type T = number\nconst T: 1", [t0, t1]);
16+
verify.singleReferenceGroup("type T = number\nconst T: 1", [v0, v1]);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
///<reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
// @Filename: a.js
5+
6+
/////** @typedef {number} */
7+
////const [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 1;
8+
9+
/////** @type {[|T|]} */
10+
////const n = [|T|];
11+
12+
verify.singleReferenceGroup("type T = number\nconst T: 1");
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
///<reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
// @Filename: a.js
5+
6+
/////**
7+
//// * Doc comment
8+
//// * @typedef /*def*/[|{| "isWriteAccess": true, "isDefinition": true |}Product|]
9+
//// * @property {string} title
10+
//// */
11+
12+
/////**
13+
//// * @type {/*use*/[|Product|]}
14+
//// */
15+
////const product = null;
16+
17+
const desc = `type Product = {
18+
title: string;
19+
}`;
20+
21+
verify.quickInfoAt("use", desc, "Doc comment");
22+
23+
verify.goToDefinition("use", "def");
24+
25+
verify.rangesAreOccurrences();
26+
verify.rangesAreDocumentHighlights();
27+
verify.singleReferenceGroup(desc);
28+
verify.rangesAreRenameLocations();

0 commit comments

Comments
 (0)