Support services for @typedef (#16087)

* Support services for @typedef

* Ensure JSDocTypeReference has SemanticMeaning.Type

* Get SemanticMeaning right
This commit is contained in:
Andy 2017-05-26 09:52:46 -07:00 committed by GitHub
parent 6972766e91
commit 3cd9f3d2d4
8 changed files with 97 additions and 11 deletions

View file

@ -2102,6 +2102,7 @@ namespace ts {
}
export interface JSDocTag extends Node {
parent: JSDoc;
atToken: AtToken;
tagName: Identifier;
comment: string | undefined;
@ -2132,6 +2133,7 @@ namespace ts {
}
export interface JSDocTypedefTag extends JSDocTag, NamedDeclaration {
parent: JSDoc;
kind: SyntaxKind.JSDocTypedefTag;
fullName?: JSDocNamespaceDeclaration | Identifier;
name?: Identifier;
@ -2140,6 +2142,7 @@ namespace ts {
}
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
parent: JSDoc;
kind: SyntaxKind.JSDocPropertyTag;
name: Identifier;
typeExpression: JSDocTypeExpression;

View file

@ -288,6 +288,14 @@ namespace ts {
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
}
export function isJSDoc(node: Node): node is JSDoc {
return node.kind === SyntaxKind.JSDocComment;
}
export function isJSDocTypedefTag(node: Node): node is JSDocTypedefTag {
return node.kind === SyntaxKind.JSDocTypedefTag;
}
export function isJSDocTag(node: Node) {
return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
}
@ -1551,6 +1559,10 @@ namespace ts {
}
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
if (isJSDocTypedefTag(node)) {
return [node.parent];
}
let cache: (JSDoc | JSDocTag)[] = node.jsDocCache;
if (!cache) {
getJSDocsWorker(node);

View file

@ -784,7 +784,8 @@ namespace ts.FindAllReferences.Core {
return;
}
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, /*fullStart*/ state.options.findInComments || container.jsDoc !== undefined)) {
const fullStart = state.options.findInComments || container.jsDoc !== undefined || forEach(search.symbol.declarations, d => d.kind === ts.SyntaxKind.JSDocTypedefTag);
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, fullStart)) {
getReferencesAtLocation(sourceFile, position, search, state);
}
}

View file

@ -8,7 +8,7 @@ namespace ts.GoToDefinition {
if (referenceFile) {
return [getDefinitionInfoForFileReference(comment.fileName, referenceFile.fileName)];
}
return undefined;
// Might still be on jsdoc, so keep looking.
}
// Type reference directives

View file

@ -39,13 +39,14 @@ namespace ts {
case SyntaxKind.TypeLiteral:
return SemanticMeaning.Type;
case SyntaxKind.JSDocTypedefTag:
// If it has no name node, it shares the name with the value declaration below it.
return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type : SemanticMeaning.Type;
case SyntaxKind.EnumMember:
case SyntaxKind.ClassDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type;
case SyntaxKind.EnumDeclaration:
return SemanticMeaning.All;
case SyntaxKind.ModuleDeclaration:
if (isAmbientModule(<ModuleDeclaration>node)) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
@ -57,6 +58,7 @@ namespace ts {
return SemanticMeaning.Namespace;
}
case SyntaxKind.EnumDeclaration:
case SyntaxKind.NamedImports:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
@ -70,7 +72,7 @@ namespace ts {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
return SemanticMeaning.All;
}
export function getMeaningFromLocation(node: Node): SemanticMeaning {
@ -78,7 +80,7 @@ namespace ts {
return SemanticMeaning.Value;
}
else if (node.parent.kind === SyntaxKind.ExportAssignment) {
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
return SemanticMeaning.All;
}
else if (isInRightSideOfImport(node)) {
return getMeaningFromRightHandSideOfImportEquals(node);
@ -162,10 +164,22 @@ namespace ts {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeReference ||
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent)) ||
(node.kind === SyntaxKind.ThisKeyword && !isPartOfExpression(node)) ||
node.kind === SyntaxKind.ThisType;
switch (node.kind) {
case SyntaxKind.ThisKeyword:
return !isPartOfExpression(node);
case SyntaxKind.ThisType:
return true;
}
switch (node.parent.kind) {
case SyntaxKind.TypeReference:
case SyntaxKind.JSDocTypeReference:
return true;
case SyntaxKind.ExpressionWithTypeArguments:
return !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent);
}
return false;
}
export function isCallExpressionTarget(node: Node): boolean {

View file

@ -0,0 +1,16 @@
///<reference path="fourslash.ts" />
// @allowJs: true
// @Filename: a.js
/////** @typedef {number} [|{| "isWriteAccess": true, "isDefinition": true |}T|] */
////const [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 1;
/////** @type {[|T|]} */
////const n = [|T|];
const [t0, v0, t1, v1] = test.ranges();
verify.singleReferenceGroup("type T = number\nconst T: 1", [t0, t1]);
verify.singleReferenceGroup("type T = number\nconst T: 1", [v0, v1]);

View file

@ -0,0 +1,12 @@
///<reference path="fourslash.ts" />
// @allowJs: true
// @Filename: a.js
/////** @typedef {number} */
////const [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 1;
/////** @type {[|T|]} */
////const n = [|T|];
verify.singleReferenceGroup("type T = number\nconst T: 1");

View file

@ -0,0 +1,28 @@
///<reference path="fourslash.ts" />
// @allowJs: true
// @Filename: a.js
/////**
//// * Doc comment
//// * @typedef /*def*/[|{| "isWriteAccess": true, "isDefinition": true |}Product|]
//// * @property {string} title
//// */
/////**
//// * @type {/*use*/[|Product|]}
//// */
////const product = null;
const desc = `type Product = {
title: string;
}`;
verify.quickInfoAt("use", desc, "Doc comment");
verify.goToDefinition("use", "def");
verify.rangesAreOccurrences();
verify.rangesAreDocumentHighlights();
verify.singleReferenceGroup(desc);
verify.rangesAreRenameLocations();