diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 9afbdd01fd3..aef2afbff42 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -801,7 +801,7 @@ namespace FourSlash { } } - public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string) { + public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) { const details = this.getCompletionEntryDetails(entryName); assert(details, "no completion entry available"); @@ -815,6 +815,14 @@ namespace FourSlash { if (kind !== undefined) { assert.equal(details.kind, kind, this.assertionMessageAtLastKnownMarker("completion entry kind")); } + + if (tags !== undefined) { + assert.equal(details.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags")); + ts.zipWith(tags, details.tags, (expectedTag, actualTag) => { + assert.equal(expectedTag.name, actualTag.name); + assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name)); + }); + } } public verifyReferencesAre(expectedReferences: Range[]) { @@ -3404,8 +3412,8 @@ namespace FourSlashInterface { this.state.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); } - public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string) { - this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind); + public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) { + this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind, tags); } /** diff --git a/src/server/protocol.ts b/src/server/protocol.ts index d3f81fcbba7..d4141852d12 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1530,6 +1530,11 @@ namespace ts.server.protocol { * Documentation strings for the symbol. */ documentation: SymbolDisplayPart[]; + + /** + * JSDoc tags for the symbol. + */ + tags: JSDocTagInfo[]; } export interface CompletionsResponse extends Response { diff --git a/src/services/completions.ts b/src/services/completions.ts index b710aa8cd78..7b80c7b7d2f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -759,13 +759,14 @@ namespace ts.Completions { const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined); if (symbol) { - const { displayParts, documentation, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All); + const { displayParts, documentation, symbolKind, jsDocTags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All); return { name: entryName, kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), kind: symbolKind, displayParts, - documentation + documentation, + tags: jsDocTags }; } } @@ -778,7 +779,8 @@ namespace ts.Completions { kind: ScriptElementKind.keyword, kindModifiers: ScriptElementKindModifier.none, displayParts: [displayPart(entryName, SymbolDisplayPartKind.keyword)], - documentation: undefined + documentation: undefined, + tags: undefined }; } diff --git a/src/services/types.ts b/src/services/types.ts index ec621a99169..a497e0f7a7f 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -583,6 +583,7 @@ namespace ts { kindModifiers: string; // see ScriptElementKindModifier, comma separated displayParts: SymbolDisplayPart[]; documentation: SymbolDisplayPart[]; + tags: JSDocTagInfo[]; } export interface OutliningSpan { diff --git a/tests/baselines/reference/jsDocTags.baseline b/tests/baselines/reference/jsDocTags.baseline index 6674b49b06c..4140fa6bfca 100644 --- a/tests/baselines/reference/jsDocTags.baseline +++ b/tests/baselines/reference/jsDocTags.baseline @@ -2,13 +2,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 898 + "position": 981 }, "quickInfo": { "kind": "constructor", "kindModifiers": "", "textSpan": { - "start": 898, + "start": 981, "length": 3 }, "displayParts": [ @@ -78,19 +78,19 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 902 + "position": 985 } }, { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 906 + "position": 989 }, "quickInfo": { "kind": "class", "kindModifiers": "", "textSpan": { - "start": 906, + "start": 989, "length": 3 }, "displayParts": [ @@ -124,13 +124,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 910 + "position": 993 }, "quickInfo": { "kind": "method", "kindModifiers": "static", "textSpan": { - "start": 910, + "start": 993, "length": 7 }, "displayParts": [ @@ -200,19 +200,19 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 918 + "position": 1001 } }, { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 925 + "position": 1008 }, "quickInfo": { "kind": "method", "kindModifiers": "", "textSpan": { - "start": 925, + "start": 1008, "length": 7 }, "displayParts": [ @@ -277,19 +277,19 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 933 + "position": 1016 } }, { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 940 + "position": 1023 }, "quickInfo": { "kind": "method", "kindModifiers": "", "textSpan": { - "start": 940, + "start": 1023, "length": 7 }, "displayParts": [ @@ -349,19 +349,19 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 948 + "position": 1031 } }, { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 955 + "position": 1038 }, "quickInfo": { "kind": "method", "kindModifiers": "", "textSpan": { - "start": 955, + "start": 1038, "length": 7 }, "displayParts": [ @@ -442,13 +442,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 970 + "position": 1053 }, "quickInfo": { "kind": "property", "kindModifiers": "", "textSpan": { - "start": 970, + "start": 1053, "length": 9 }, "displayParts": [ @@ -505,13 +505,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 985 + "position": 1068 }, "quickInfo": { "kind": "property", "kindModifiers": "", "textSpan": { - "start": 985, + "start": 1068, "length": 9 }, "displayParts": [ @@ -580,13 +580,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/jsDocTags.ts", - "position": 1000 + "position": 1083 }, "quickInfo": { "kind": "method", "kindModifiers": "", "textSpan": { - "start": 1000, + "start": 1083, "length": 7 }, "displayParts": [ @@ -647,5 +647,25 @@ } ] } + }, + { + "marker": { + "fileName": "/tests/cases/fourslash/jsDocTags.ts", + "position": 1104 + }, + "quickInfo": { + "kind": "", + "kindModifiers": "", + "textSpan": { + "start": 1098, + "length": 6 + }, + "displayParts": [ + { + "text": "any", + "kind": "keyword" + } + ] + } } ] \ No newline at end of file diff --git a/tests/cases/fourslash/jsDocTags.ts b/tests/cases/fourslash/jsDocTags.ts index 4484e74cda5..dbcb7c2d8f7 100644 --- a/tests/cases/fourslash/jsDocTags.ts +++ b/tests/cases/fourslash/jsDocTags.ts @@ -44,6 +44,10 @@ //// method4(foo: string): number { return 3; } //// /** @mytag */ //// method5() {} +//// /** method documentation +//// * @mytag a JSDoc tag +//// */ +//// newMethod() {} //// } //// var foo = new /*1*/Foo(/*10*/4); //// /*2*/Foo./*3*/method1(/*11*/); @@ -53,6 +57,7 @@ //// foo./*7*/property1; //// foo./*8*/property2; //// foo./*9*/method5(); +//// foo.newMet/*14*/ verify.baselineQuickInfo(); @@ -65,3 +70,6 @@ goTo.marker("12"); verify.currentSignatureHelpTagsAre([{name: "mytag", text:""}]) goTo.marker("13"); verify.currentSignatureHelpTagsAre([]) + +goTo.marker('14'); +verify.completionEntryDetailIs("newMethod", "(method) Foo.newMethod(): void", "method documentation", "method", [{name: "mytag", text: "a JSDoc tag"}]); \ No newline at end of file