Fix JsDocTags inheritage and setter/getter quickInfo (#46801)

* tmp

* fix jsdoc inheritage for property and setter/getter

* fix test

* fix test

* fix mirrors

* add more tests

* add tests of jsdoc for intance of class
This commit is contained in:
Song Gao
2022-01-26 07:43:12 +08:00
committed by GitHub
parent f84a67f29c
commit 0673f0288c
16 changed files with 3281 additions and 82 deletions

View File

@@ -1397,11 +1397,11 @@ namespace FourSlash {
}));
}
public verifyQuickInfoAt(markerName: string | Range, expectedText: string, expectedDocumentation?: string) {
public verifyQuickInfoAt(markerName: string | Range, expectedText: string, expectedDocumentation?: string, expectedTags?: {name: string; text: string;}[]) {
if (typeof markerName === "string") this.goToMarker(markerName);
else this.goToRangeStart(markerName);
this.verifyQuickInfoString(expectedText, expectedDocumentation);
this.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags);
}
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
@@ -1420,16 +1420,29 @@ namespace FourSlash {
}
}
public verifyQuickInfoString(expectedText: string, expectedDocumentation?: string) {
public verifyQuickInfoString(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) {
if (expectedDocumentation === "") {
throw new Error("Use 'undefined' instead");
throw new Error("Use 'undefined' instead of empty string for `expectedDocumentation`");
}
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : "";
const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : "";
const actualQuickInfoText = ts.displayPartsToString(actualQuickInfo?.displayParts);
const actualQuickInfoDocumentation = ts.displayPartsToString(actualQuickInfo?.documentation);
const actualQuickInfoTags = actualQuickInfo?.tags?.map(tag => ({ name: tag.name, text: ts.displayPartsToString(tag.text) }));
assert.equal(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text"));
assert.equal(actualQuickInfoDocumentation, expectedDocumentation || "", this.assertionMessageAtLastKnownMarker("quick info doc"));
if (!expectedTags) {
// Skip if `expectedTags` is not given
}
else if (!actualQuickInfoTags) {
assert.equal(actualQuickInfoTags, expectedTags, this.messageAtLastKnownMarker("QuickInfo tags"));
}
else {
ts.zipWith(expectedTags, actualQuickInfoTags, (expectedTag, actualTag) => {
assert.equal(expectedTag.name, actualTag.name);
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
});
}
}
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan,

View File

@@ -259,12 +259,12 @@ namespace FourSlashInterface {
this.state.verifyInlayHints(expected, span, preference);
}
public quickInfoIs(expectedText: string, expectedDocumentation?: string) {
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
public quickInfoIs(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) {
this.state.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags);
}
public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string) {
this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation);
public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) {
this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation, expectedTags);
}
public quickInfos(namesAndTexts: { [name: string]: string }) {

View File

@@ -299,6 +299,9 @@ namespace ts {
contextualGetAccessorDocumentationComment?: SymbolDisplayPart[];
contextualSetAccessorDocumentationComment?: SymbolDisplayPart[];
contextualGetAccessorTags?: JSDocTagInfo[];
contextualSetAccessorTags?: JSDocTagInfo[];
constructor(flags: SymbolFlags, name: __String) {
this.flags = flags;
this.escapedName = name;
@@ -343,13 +346,11 @@ namespace ts {
switch (context?.kind) {
case SyntaxKind.GetAccessor:
if (!this.contextualGetAccessorDocumentationComment) {
this.contextualGetAccessorDocumentationComment = emptyArray;
this.contextualGetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isGetAccessor), checker);
}
return this.contextualGetAccessorDocumentationComment;
case SyntaxKind.SetAccessor:
if (!this.contextualSetAccessorDocumentationComment) {
this.contextualSetAccessorDocumentationComment = emptyArray;
this.contextualSetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isSetAccessor), checker);
}
return this.contextualSetAccessorDocumentationComment;
@@ -360,11 +361,28 @@ namespace ts {
getJsDocTags(checker?: TypeChecker): JSDocTagInfo[] {
if (this.tags === undefined) {
this.tags = JsDoc.getJsDocTagsFromDeclarations(this.declarations, checker);
this.tags = getJsDocTagsOfDeclarations(this.declarations, checker);
}
return this.tags;
}
getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
switch (context?.kind) {
case SyntaxKind.GetAccessor:
if (!this.contextualGetAccessorTags) {
this.contextualGetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isGetAccessor), checker);
}
return this.contextualGetAccessorTags;
case SyntaxKind.SetAccessor:
if (!this.contextualSetAccessorTags) {
this.contextualSetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isSetAccessor), checker);
}
return this.contextualSetAccessorTags;
default:
return this.getJsDocTags(checker);
}
}
}
class TokenObject<TKind extends SyntaxKind> extends TokenOrIdentifierObject implements Token<TKind> {
@@ -564,10 +582,7 @@ namespace ts {
}
getJsDocTags(): JSDocTagInfo[] {
if (this.jsDocTags === undefined) {
this.jsDocTags = this.declaration ? getJsDocTagsOfSignature(this.declaration, this.checker) : [];
}
return this.jsDocTags;
return this.jsDocTags || (this.jsDocTags = getJsDocTagsOfDeclarations(singleElementArray(this.declaration), this.checker));
}
}
@@ -580,12 +595,25 @@ namespace ts {
return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc");
}
function getJsDocTagsOfSignature(declaration: Declaration, checker: TypeChecker): JSDocTagInfo[] {
let tags = JsDoc.getJsDocTagsFromDeclarations([declaration], checker);
if (tags.length === 0 || hasJSDocInheritDocTag(declaration)) {
const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => symbol.declarations?.length === 1 ? symbol.getJsDocTags() : undefined);
if (inheritedTags) {
tags = [...inheritedTags, ...tags];
function getJsDocTagsOfDeclarations(declarations: Declaration[] | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
if (!declarations) return emptyArray;
let tags = JsDoc.getJsDocTagsFromDeclarations(declarations, checker);
if (checker && (tags.length === 0 || declarations.some(hasJSDocInheritDocTag))) {
const seenSymbols = new Set<Symbol>();
for (const declaration of declarations) {
const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => {
if (!seenSymbols.has(symbol)) {
seenSymbols.add(symbol);
if (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) {
return symbol.getContextualJsDocTags(declaration, checker);
}
return symbol.declarations?.length === 1 ? symbol.getJsDocTags() : undefined;
}
});
if (inheritedTags) {
tags = [...inheritedTags, ...tags];
}
}
}
return tags;
@@ -601,6 +629,9 @@ namespace ts {
const inheritedDocs = findBaseOfDeclaration(checker, declaration, symbol => {
if (!seenSymbols.has(symbol)) {
seenSymbols.add(symbol);
if (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) {
return symbol.getContextualDocumentationComment(declaration, checker);
}
return symbol.getDocumentationComment(checker);
}
});

View File

@@ -58,6 +58,8 @@ namespace ts.SymbolDisplay {
return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement;
}
if (flags & SymbolFlags.Function) return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement;
// FIXME: getter and setter use the same symbol. And it is rare to use only setter without getter, so in most cases the symbol always has getter flag.
// So, even when the location is just on the declaration of setter, this function returns getter.
if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement;
if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement;
if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement;
@@ -154,9 +156,24 @@ namespace ts.SymbolDisplay {
// Class at constructor site need to be shown as constructor apart from property,method, vars
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias) {
// If it is accessor they are allowed only if location is at name of the accessor
// If symbol is accessor, they are allowed only if location is at declaration identifier of the accessor
if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) {
symbolKind = ScriptElementKind.memberVariableElement;
const declaration = find(symbol.declarations as ((GetAccessorDeclaration | SetAccessorDeclaration)[]), declaration => declaration.name === location);
if (declaration) {
switch(declaration.kind){
case SyntaxKind.GetAccessor:
symbolKind = ScriptElementKind.memberGetAccessorElement;
break;
case SyntaxKind.SetAccessor:
symbolKind = ScriptElementKind.memberSetAccessorElement;
break;
default:
Debug.assertNever(declaration);
}
}
else {
symbolKind = ScriptElementKind.memberVariableElement;
}
}
let signature: Signature | undefined;
@@ -492,6 +509,8 @@ namespace ts.SymbolDisplay {
// For properties, variables and local vars: show the type
if (symbolKind === ScriptElementKind.memberVariableElement ||
symbolKind === ScriptElementKind.memberGetAccessorElement ||
symbolKind === ScriptElementKind.memberSetAccessorElement ||
symbolKind === ScriptElementKind.jsxAttribute ||
symbolFlags & SymbolFlags.Variable ||
symbolKind === ScriptElementKind.localVariableElement ||
@@ -566,7 +585,7 @@ namespace ts.SymbolDisplay {
}
if (tags.length === 0 && !hasMultipleSignatures) {
tags = symbol.getJsDocTags(typeChecker);
tags = symbol.getContextualJsDocTags(enclosingDeclaration, typeChecker);
}
if (documentation.length === 0 && documentationFromAlias) {

View File

@@ -44,6 +44,8 @@ namespace ts {
/* @internal */
getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[]
getJsDocTags(checker?: TypeChecker): JSDocTagInfo[];
/* @internal */
getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[];
}
export interface Type {

View File

@@ -191,7 +191,7 @@
"name": "6"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "public",
"textSpan": {
"start": 245,
@@ -203,7 +203,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -341,7 +341,7 @@
"name": "10"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "public",
"textSpan": {
"start": 334,
@@ -353,7 +353,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -641,7 +641,7 @@
"name": "18"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "private",
"textSpan": {
"start": 624,
@@ -653,7 +653,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -791,7 +791,7 @@
"name": "22"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "private",
"textSpan": {
"start": 717,
@@ -803,7 +803,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -1146,7 +1146,7 @@
"name": "32"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "static",
"textSpan": {
"start": 1077,
@@ -1158,7 +1158,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -1296,7 +1296,7 @@
"name": "37"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "static",
"textSpan": {
"start": 1162,
@@ -1308,7 +1308,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -1586,7 +1586,7 @@
"name": "46"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "public",
"textSpan": {
"start": 1346,
@@ -1598,7 +1598,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -1726,7 +1726,7 @@
"name": "48"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "public",
"textSpan": {
"start": 1416,
@@ -1738,7 +1738,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -2006,7 +2006,7 @@
"name": "53"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "private",
"textSpan": {
"start": 1599,
@@ -2018,7 +2018,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -2146,7 +2146,7 @@
"name": "55"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "private",
"textSpan": {
"start": 1673,
@@ -2158,7 +2158,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -2426,7 +2426,7 @@
"name": "60"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "static",
"textSpan": {
"start": 1851,
@@ -2438,7 +2438,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -2566,7 +2566,7 @@
"name": "62"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "static",
"textSpan": {
"start": 1917,
@@ -2578,7 +2578,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{

View File

@@ -6,7 +6,7 @@
"name": "1"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "public",
"textSpan": {
"start": 25,
@@ -18,7 +18,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -64,7 +64,7 @@
"name": "1s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "public",
"textSpan": {
"start": 72,
@@ -76,7 +76,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -122,7 +122,7 @@
"name": "2"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "private",
"textSpan": {
"start": 118,
@@ -134,7 +134,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -180,7 +180,7 @@
"name": "2s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "private",
"textSpan": {
"start": 167,
@@ -192,7 +192,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -238,7 +238,7 @@
"name": "21"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "protected",
"textSpan": {
"start": 216,
@@ -250,7 +250,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -296,7 +296,7 @@
"name": "21s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "protected",
"textSpan": {
"start": 269,
@@ -308,7 +308,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -354,7 +354,7 @@
"name": "3"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "static",
"textSpan": {
"start": 317,
@@ -366,7 +366,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -412,7 +412,7 @@
"name": "3s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "static",
"textSpan": {
"start": 364,
@@ -424,7 +424,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -470,7 +470,7 @@
"name": "4"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "private,static",
"textSpan": {
"start": 418,
@@ -482,7 +482,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -528,7 +528,7 @@
"name": "4s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "private,static",
"textSpan": {
"start": 480,
@@ -540,7 +540,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{
@@ -586,7 +586,7 @@
"name": "41"
},
"quickInfo": {
"kind": "property",
"kind": "getter",
"kindModifiers": "protected,static",
"textSpan": {
"start": 542,
@@ -598,7 +598,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "getter",
"kind": "text"
},
{
@@ -644,7 +644,7 @@
"name": "41s"
},
"quickInfo": {
"kind": "property",
"kind": "setter",
"kindModifiers": "protected,static",
"textSpan": {
"start": 608,
@@ -656,7 +656,7 @@
"kind": "punctuation"
},
{
"text": "property",
"text": "setter",
"kind": "text"
},
{

View File

@@ -0,0 +1,802 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 75,
"name": "1"
},
"quickInfo": {
"kind": "getter",
"kindModifiers": "",
"textSpan": {
"start": 75,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "getter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "getter A",
"kind": "text"
}
],
"tags": [
{
"name": "returns",
"text": [
{
"text": "return A",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 205,
"name": "2"
},
"quickInfo": {
"kind": "setter",
"kindModifiers": "",
"textSpan": {
"start": 205,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "setter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "setter A",
"kind": "text"
}
],
"tags": [
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo A",
"kind": "text"
}
]
},
{
"name": "todo",
"text": [
{
"text": "empty jsdoc",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 340,
"name": "3"
},
"quickInfo": {
"kind": "getter",
"kindModifiers": "",
"textSpan": {
"start": 340,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "getter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "B",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "getter B",
"kind": "text"
}
],
"tags": [
{
"name": "returns",
"text": [
{
"text": "return B",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 445,
"name": "4"
},
"quickInfo": {
"kind": "setter",
"kindModifiers": "",
"textSpan": {
"start": 445,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "setter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "B",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "setter B",
"kind": "text"
}
],
"tags": [
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo B",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 607,
"name": "5"
},
"quickInfo": {
"kind": "setter",
"kindModifiers": "",
"textSpan": {
"start": 607,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "setter",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "D",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "setter D",
"kind": "text"
}
],
"tags": [
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo D",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 636,
"name": "6"
},
"quickInfo": {
"kind": "property",
"kindModifiers": "",
"textSpan": {
"start": 636,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "getter A",
"kind": "text"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": "setter A",
"kind": "text"
}
],
"tags": [
{
"name": "returns",
"text": [
{
"text": "return A",
"kind": "text"
}
]
},
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo A",
"kind": "text"
}
]
},
{
"name": "todo",
"text": [
{
"text": "empty jsdoc",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 653,
"name": "7"
},
"quickInfo": {
"kind": "property",
"kindModifiers": "",
"textSpan": {
"start": 653,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "B",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "getter B",
"kind": "text"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": "setter B",
"kind": "text"
}
],
"tags": [
{
"name": "returns",
"text": [
{
"text": "return B",
"kind": "text"
}
]
},
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo B",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 670,
"name": "8"
},
"quickInfo": {
"kind": "property",
"kindModifiers": "",
"textSpan": {
"start": 670,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "getter A",
"kind": "text"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": "setter A",
"kind": "text"
}
],
"tags": [
{
"name": "returns",
"text": [
{
"text": "return A",
"kind": "text"
}
]
},
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo A",
"kind": "text"
}
]
},
{
"name": "todo",
"text": [
{
"text": "empty jsdoc",
"kind": "text"
}
]
}
]
}
},
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocGetterSetter.ts",
"position": 687,
"name": "9"
},
"quickInfo": {
"kind": "property",
"kindModifiers": "",
"textSpan": {
"start": 687,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "D",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "x",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
}
],
"documentation": [
{
"text": "setter D",
"kind": "text"
}
],
"tags": [
{
"name": "param",
"text": [
{
"text": "value",
"kind": "parameterName"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo D",
"kind": "text"
}
]
}
]
}
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,17 @@
"text": "this is the name of blabla \n- use blabla",
"kind": "text"
}
],
"tags": [
{
"name": "example",
"text": [
{
"text": "blabla",
"kind": "text"
}
]
}
]
}
},
@@ -122,6 +133,17 @@
"text": "this is the name of blabla \n- use blabla",
"kind": "text"
}
],
"tags": [
{
"name": "example",
"text": [
{
"text": "blabla",
"kind": "text"
}
]
}
]
}
}

View File

@@ -11,6 +11,6 @@
////[|const { /*g1*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}g|], /*s1*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}s|] } = new C();|]
const [g0Def, g0, s0Def, s0, gs1Def, g1, s1] = test.ranges();
verify.quickInfoAt(g0, "(property) C.g: number");
verify.quickInfoAt(s0, "(property) C.s: number");
verify.quickInfoAt(g0, "(getter) C.g: number");
verify.quickInfoAt(s0, "(setter) C.s: number");
verify.baselineFindAllReferences('g0', 'g1', 's0', 's1')

View File

@@ -399,9 +399,9 @@ declare namespace FourSlashInterface {
baselineRename(marker: string, options: RenameOptions): void;
/** Verify the quick info available at the current marker. */
quickInfoIs(expectedText: string, expectedDocumentation?: string): void;
quickInfoIs(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]): void;
/** Goto a marker and call `quickInfoIs`. */
quickInfoAt(markerName: string | Range, expectedText?: string, expectedDocumentation?: string): void;
quickInfoAt(markerName: string | Range, expectedText?: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]): void;
/**
* Call `quickInfoAt` for each pair in the object.
* (If the value is an array, it is [expectedText, expectedDocumentation].)

View File

@@ -17,7 +17,7 @@
//// }
goTo.marker("1");
verify.quickInfoIs("(property) Test.value: any", "Getter text");
verify.quickInfoIs("(getter) Test.value: any", "Getter text");
goTo.marker("2");
verify.quickInfoIs("(property) Test.value: any", "Setter text");
verify.quickInfoIs("(setter) Test.value: any", "Setter text");

View File

@@ -15,6 +15,6 @@
//// instance./*setterUse*/myValue = instance./*getterUse*/myValue;
verify.quickInfoAt("getterUse", "(property) C.myValue: Promise<string>");
verify.quickInfoAt("getterDef", "(property) C.myValue: Promise<string>");
verify.quickInfoAt("getterDef", "(getter) C.myValue: Promise<string>");
verify.quickInfoAt("setterUse", "(property) C.myValue: string | Promise<string>");
verify.quickInfoAt("setterDef", "(property) C.myValue: string | Promise<string>");
verify.quickInfoAt("setterDef", "(setter) C.myValue: string | Promise<string>");

View File

@@ -0,0 +1,48 @@
/// <reference path='fourslash.ts' />
//// class A {
//// /**
//// * getter A
//// * @returns return A
//// */
//// get /*1*/x(): string {
//// return "";
//// }
//// /**
//// * setter A
//// * @param value foo A
//// * @todo empty jsdoc
//// */
//// set /*2*/x(value) { }
//// }
//// // override both getter and setter
//// class B extends A {
//// /**
//// * getter B
//// * @returns return B
//// */
//// get /*3*/x(): string {
//// return "";
//// }
//// /**
//// * setter B
//// * @param value foo B
//// */
//// set /*4*/x(vale) { }
//// }
//// // not override
//// class C extends A { }
//// // only override setter
//// class D extends A {
//// /**
//// * setter D
//// * @param value foo D
//// */
//// set /*5*/x(val: string) { }
//// }
//// new A()./*6*/x = "1";
//// new B()./*7*/x = "1";
//// new C()./*8*/x = "1";
//// new D()./*9*/x = "1";
verify.baselineQuickInfo();

View File

@@ -0,0 +1,108 @@
/// <reference path='fourslash.ts' />
//// interface A {
//// /**
//// * @description A.foo1
//// */
//// foo1: number;
//// /**
//// * @description A.foo2
//// */
//// foo2: (para1: string) => number;
//// }
////
//// interface B {
//// /**
//// * @description B.foo1
//// */
//// foo1: number;
//// /**
//// * @description B.foo2
//// */
//// foo2: (para2: string) => number;
//// }
////
//// // implement multi interfaces with duplicate name
//// // method for function signature
//// class C implements A, B {
//// /*1*/foo1: number = 1;
//// /*2*/foo2(q: string) { return 1 }
//// }
////
//// // implement multi interfaces with duplicate name
//// // property for function signature
//// class D implements A, B {
//// /*3*/foo1: number = 1;
//// /*4*/foo2 = (q: string) => { return 1 }
//// }
////
//// new C()./*5*/foo1;
//// new C()./*6*/foo2;
//// new D()./*7*/foo1;
//// new D()./*8*/foo2;
////
//// class Base1 {
//// /**
//// * @description Base1.foo1
//// */
//// foo1: number = 1;
////
//// /**
//// *
//// * @param q Base1.foo2 parameter
//// * @returns Base1.foo2 return
//// */
//// foo2(q: string) { return 1 }
//// }
////
//// // extends class and implement interfaces with duplicate name
//// // property override method
//// class Drived1 extends Base1 implements A {
//// /*9*/foo1: number = 1;
//// /*10*/foo2(para1: string) { return 1 };
//// }
////
//// // extends class and implement interfaces with duplicate name
//// // method override method
//// class Drived2 extends Base1 implements B {
//// /*11*/foo1: number = 1;
//// /*12*/foo2 = (para1: string) => { return 1; };
//// }
////
//// class Base2 {
//// /**
//// * @description Base2.foo1
//// */
//// foo1: number = 1;
//// /**
//// *
//// * @param q Base2.foo2 parameter
//// * @returns Base2.foo2 return
//// */
//// foo2(q: string) { return 1 }
//// }
////
//// // extends class and implement interfaces with duplicate name
//// // property override method
//// class Drived3 extends Base2 implements A {
//// /*13*/foo1: number = 1;
//// /*14*/foo2(para1: string) { return 1 };
//// }
////
//// // extends class and implement interfaces with duplicate name
//// // method override method
//// class Drived4 extends Base2 implements B {
//// /*15*/foo1: number = 1;
//// /*16*/foo2 = (para1: string) => { return 1; };
//// }
////
//// new Drived1()./*17*/foo1;
//// new Drived1()./*18*/foo2;
//// new Drived2()./*19*/foo1;
//// new Drived2()./*20*/foo2;
//// new Drived3()./*21*/foo1;
//// new Drived3()./*22*/foo2;
//// new Drived4()./*23*/foo1;
//// new Drived4()./*24*/foo2;
verify.baselineQuickInfo();