From c20e4f53eaf944abac5d47c724e60162373f24f3 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 16 Oct 2014 10:35:34 -0700 Subject: [PATCH] Produce SignatureHelpParameters from type parameters for generic help --- src/compiler/checker.ts | 9 ++-- src/compiler/types.ts | 5 ++- src/services/signatureHelp.ts | 82 +++++++++++++++++++++++++---------- 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 29ded915826..0c210421232 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1366,14 +1366,14 @@ module ts { } } - function buildDisplayForParametersAndDelimiters(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { writePunctuation(writer, SyntaxKind.OpenParenToken); - for (var i = 0; i < signature.parameters.length; i++) { + for (var i = 0; i < parameters.length; i++) { if (i > 0) { writePunctuation(writer, SyntaxKind.CommaToken); writeSpace(writer); } - buildParameterDisplay(signature.parameters[i], writer, enclosingDeclaration, flags, typeStack); + buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack); } writePunctuation(writer, SyntaxKind.CloseParenToken); } @@ -1400,7 +1400,7 @@ module ts { buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack); } - buildDisplayForParametersAndDelimiters(signature, writer, enclosingDeclaration, flags, typeStack); + buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack); buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack); } @@ -1411,6 +1411,7 @@ module ts { buildTypeDisplay: buildTypeDisplay, buildTypeParameterDisplay: buildTypeParameterDisplay, buildParameterDisplay: buildParameterDisplay, + buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters, buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters, buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters, buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 25532c94f9c..058cc309044 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -675,8 +675,9 @@ module ts { buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void; - buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]): void; - buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]): void; + buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; } export interface SymbolWriter { diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 327a61477e7..26041dbd3e0 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -293,33 +293,41 @@ module ts.SignatureHelp { function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentInfoOrTypeArgumentInfo: ListItemInfo): SignatureHelpItems { var argumentListOrTypeArgumentList = argumentInfoOrTypeArgumentInfo.list; + var parent = argumentListOrTypeArgumentList.parent; + var isTypeParameterHelp = parent.typeArguments && parent.typeArguments.pos === argumentListOrTypeArgumentList.pos; + Debug.assert(isTypeParameterHelp || parent.arguments.pos === argumentListOrTypeArgumentList.pos); + + var callTargetNode = (argumentListOrTypeArgumentList.parent).func; + var callTargetSymbol = typeInfoResolver.getSymbolInfo(callTargetNode); + var callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); var items: SignatureHelpItem[] = map(candidates, candidateSignature => { - var parameters = candidateSignature.parameters; - var parameterHelpItems: SignatureHelpParameter[] = parameters.length === 0 ? emptyArray : map(parameters, p => { - var displayParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(p, writer, argumentListOrTypeArgumentList)); + var signatureHelpParameters: SignatureHelpParameter[]; + var prefixParts: SymbolDisplayPart[] = []; + var suffixParts: SymbolDisplayPart[] = []; - var isOptional = !!(p.valueDeclaration.flags & NodeFlags.QuestionMark); + if (callTargetDisplayParts) { + prefixParts.push.apply(prefixParts, callTargetDisplayParts); + } - return { - name: p.name, - documentation: p.getDocumentationComment(), - displayParts: displayParts, - isOptional: isOptional - }; - }); + if (isTypeParameterHelp) { + prefixParts.push(punctuationPart(SyntaxKind.LessThanToken)); + var typeParameters = candidateSignature.typeParameters; + signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; + suffixParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); + var parameterParts = mapToDisplayParts(writer => + typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, argumentListOrTypeArgumentList)); + suffixParts.push.apply(suffixParts, parameterParts); + } + else { + var typeParameterParts = mapToDisplayParts(writer => + typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, argumentListOrTypeArgumentList)); + prefixParts.push.apply(prefixParts, typeParameterParts); + prefixParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + var parameters = candidateSignature.parameters; + signatureHelpParameters = parameters.length > 0 ? map(parameters, createSignatureHelpParameterForParameter) : emptyArray; + suffixParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + } - var callTargetNode = (argumentListOrTypeArgumentList.parent).func; - var callTargetSymbol = typeInfoResolver.getSymbolInfo(callTargetNode); - - var prefixParts = callTargetSymbol ? symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : []; - - var typeParameterParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, argumentListOrTypeArgumentList)); - prefixParts.push.apply(prefixParts, typeParameterParts); - prefixParts.push(punctuationPart(SyntaxKind.OpenParenToken)); - - var suffixParts = [punctuationPart(SyntaxKind.CloseParenToken)]; var returnTypeParts = mapToDisplayParts(writer => typeInfoResolver.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, argumentListOrTypeArgumentList)); suffixParts.push.apply(suffixParts, returnTypeParts); @@ -329,7 +337,7 @@ module ts.SignatureHelp { prefixDisplayParts: prefixParts, suffixDisplayParts: suffixParts, separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()], - parameters: parameterHelpItems, + parameters: signatureHelpParameters, documentation: candidateSignature.getDocumentationComment() }; }); @@ -375,6 +383,32 @@ module ts.SignatureHelp { argumentIndex: argumentIndex, argumentCount: argumentCount }; + + function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter { + var displayParts = mapToDisplayParts(writer => + typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, argumentListOrTypeArgumentList)); + + var isOptional = !!(parameter.valueDeclaration.flags & NodeFlags.QuestionMark); + + return { + name: parameter.name, + documentation: parameter.getDocumentationComment(), + displayParts: displayParts, + isOptional: isOptional + }; + } + + function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter { + var displayParts = mapToDisplayParts(writer => + typeInfoResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, argumentListOrTypeArgumentList)); + + return { + name: typeParameter.symbol.name, + documentation: emptyArray, + displayParts: displayParts, + isOptional: false + }; + } } } } \ No newline at end of file