Correctly resolve tags for function overloads (#30253)

* Correctly resolve tags for function overloads. Fixes #30181

* Better fix for #30181. Added more unit tests

* Fix commentsOverloads tests

* Fallback to first signature when doc and tags are empty
This commit is contained in:
Jean Pierre
2020-01-10 11:54:26 -05:00
committed by Nathan Shively-Sanders
parent 5fc917be2e
commit 79dcd3dba1
7 changed files with 370 additions and 41 deletions

View File

@@ -131,8 +131,8 @@ namespace ts.SymbolDisplay {
}
const displayParts: SymbolDisplayPart[] = [];
let documentation: SymbolDisplayPart[] | undefined;
let tags: JSDocTagInfo[] | undefined;
let documentation: SymbolDisplayPart[] = [];
let tags: JSDocTagInfo[] = [];
const symbolFlags = getCombinedLocalAndExportSymbolFlags(symbol);
let symbolKind = semanticMeaning & SemanticMeaning.Value ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) : ScriptElementKind.unknown;
let hasAddedSymbolInfo = false;
@@ -141,6 +141,7 @@ namespace ts.SymbolDisplay {
let printer: Printer;
let documentationFromAlias: SymbolDisplayPart[] | undefined;
let tagsFromAlias: JSDocTagInfo[] | undefined;
let hasMultipleSignatures = false;
if (location.kind === SyntaxKind.ThisKeyword && !isThisExpression) {
return { displayParts: [keywordPart(SyntaxKind.ThisKeyword)], documentation: [], symbolKind: ScriptElementKind.primitiveType, tags: undefined };
@@ -236,6 +237,7 @@ namespace ts.SymbolDisplay {
addSignatureDisplayParts(signature, allSignatures);
}
hasAddedSymbolInfo = true;
hasMultipleSignatures = allSignatures.length > 1;
}
}
else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration
@@ -268,6 +270,7 @@ namespace ts.SymbolDisplay {
addSignatureDisplayParts(signature, allSignatures);
hasAddedSymbolInfo = true;
hasMultipleSignatures = allSignatures.length > 1;
}
}
}
@@ -495,6 +498,7 @@ namespace ts.SymbolDisplay {
const allSignatures = type.getNonNullableType().getCallSignatures();
if (allSignatures.length) {
addSignatureDisplayParts(allSignatures[0], allSignatures);
hasMultipleSignatures = allSignatures.length > 1;
}
}
}
@@ -504,42 +508,47 @@ namespace ts.SymbolDisplay {
}
}
if (!documentation) {
if (documentation.length === 0 && !hasMultipleSignatures) {
documentation = symbol.getDocumentationComment(typeChecker);
tags = symbol.getJsDocTags();
if (documentation.length === 0 && symbolFlags & SymbolFlags.Property) {
// For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo`
// there documentation comments might be attached to the right hand side symbol of their declarations.
// The pattern of such special property access is that the parent symbol is the symbol of the file.
if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) {
for (const declaration of symbol.declarations) {
if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) {
continue;
}
}
const rhsSymbol = typeChecker.getSymbolAtLocation((<BinaryExpression>declaration.parent).right);
if (!rhsSymbol) {
continue;
}
if (documentation.length === 0 && symbolFlags & SymbolFlags.Property) {
// For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo`
// there documentation comments might be attached to the right hand side symbol of their declarations.
// The pattern of such special property access is that the parent symbol is the symbol of the file.
if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) {
for (const declaration of symbol.declarations) {
if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) {
continue;
}
documentation = rhsSymbol.getDocumentationComment(typeChecker);
tags = rhsSymbol.getJsDocTags();
if (documentation.length > 0) {
break;
}
const rhsSymbol = typeChecker.getSymbolAtLocation((<BinaryExpression>declaration.parent).right);
if (!rhsSymbol) {
continue;
}
documentation = rhsSymbol.getDocumentationComment(typeChecker);
tags = rhsSymbol.getJsDocTags();
if (documentation.length > 0) {
break;
}
}
}
}
if (tags.length === 0 && !hasMultipleSignatures) {
tags = symbol.getJsDocTags();
}
if (documentation.length === 0 && documentationFromAlias) {
documentation = documentationFromAlias;
}
if (tags!.length === 0 && tagsFromAlias) {
if (tags.length === 0 && tagsFromAlias) {
tags = tagsFromAlias;
}
return { displayParts, documentation, symbolKind, tags: tags!.length === 0 ? undefined : tags };
return { displayParts, documentation, symbolKind, tags: tags.length === 0 ? undefined : tags };
function getPrinter() {
if (!printer) {
@@ -620,9 +629,13 @@ namespace ts.SymbolDisplay {
displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads"));
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
const docComment = signature.getDocumentationComment(typeChecker);
documentation = docComment.length === 0 ? undefined : docComment;
documentation = signature.getDocumentationComment(typeChecker);
tags = signature.getJsDocTags();
if (allSignatures.length > 1 && documentation.length === 0 && tags.length === 0) {
documentation = allSignatures[0].getDocumentationComment(typeChecker);
tags = allSignatures[0].getJsDocTags();
}
}
function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined) {