Skip to content

Commit a1e69b0

Browse files
committed
Merge pull request #915 from Microsoft/sigHelp
Basic generic signature help
2 parents a537cb3 + d5709ed commit a1e69b0

File tree

9 files changed

+247
-186
lines changed

9 files changed

+247
-186
lines changed

src/compiler/checker.ts

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -993,16 +993,34 @@ module ts {
993993
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
994994
var _displayBuilder: SymbolDisplayBuilder;
995995
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
996-
// Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
997-
// Meaning needs to be specified if the enclosing declaration is given
996+
/**
997+
* Writes only the name of the symbol out to the writer. Uses the original source text
998+
* for the name of the symbol if it is available to match how the user inputted the name.
999+
*/
1000+
function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void {
1001+
if (symbol.declarations && symbol.declarations.length > 0) {
1002+
var declaration = symbol.declarations[0];
1003+
if (declaration.name) {
1004+
writer.writeSymbol(identifierToString(declaration.name), symbol);
1005+
return;
1006+
}
1007+
}
1008+
1009+
writer.writeSymbol(symbol.name, symbol);
1010+
}
1011+
1012+
/**
1013+
* Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
1014+
* Meaning needs to be specified if the enclosing declaration is given
1015+
*/
9981016
function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void {
9991017
var parentSymbol: Symbol;
1000-
function writeSymbolName(symbol: Symbol): void {
1018+
function appendParentTypeArgumentsAndSymbolName(symbol: Symbol): void {
10011019
if (parentSymbol) {
10021020
// Write type arguments of instantiated class/interface here
10031021
if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) {
10041022
if (symbol.flags & SymbolFlags.Instantiated) {
1005-
buildTypeArgumentListDisplay(getTypeParametersOfClassOrInterface(parentSymbol),
1023+
buildDisplayForTypeArgumentsAndDelimiters(getTypeParametersOfClassOrInterface(parentSymbol),
10061024
(<TransientSymbol>symbol).mapper, writer, enclosingDeclaration);
10071025
}
10081026
else {
@@ -1012,15 +1030,7 @@ module ts {
10121030
writePunctuation(writer, SyntaxKind.DotToken);
10131031
}
10141032
parentSymbol = symbol;
1015-
if (symbol.declarations && symbol.declarations.length > 0) {
1016-
var declaration = symbol.declarations[0];
1017-
if (declaration.name) {
1018-
writer.writeSymbol(identifierToString(declaration.name), symbol);
1019-
return;
1020-
}
1021-
}
1022-
1023-
writer.writeSymbol(symbol.name, symbol);
1033+
appendSymbolNameOnly(symbol, writer);
10241034
}
10251035

10261036
// Let the writer know we just wrote out a symbol. The declaration emitter writer uses
@@ -1046,7 +1056,7 @@ module ts {
10461056

10471057
if (accessibleSymbolChain) {
10481058
for (var i = 0, n = accessibleSymbolChain.length; i < n; i++) {
1049-
writeSymbolName(accessibleSymbolChain[i]);
1059+
appendParentTypeArgumentsAndSymbolName(accessibleSymbolChain[i]);
10501060
}
10511061
}
10521062
else {
@@ -1060,7 +1070,7 @@ module ts {
10601070
return;
10611071
}
10621072

1063-
writeSymbolName(symbol);
1073+
appendParentTypeArgumentsAndSymbolName(symbol);
10641074
}
10651075
}
10661076
}
@@ -1074,7 +1084,7 @@ module ts {
10741084
return;
10751085
}
10761086

1077-
return writeSymbolName(symbol);
1087+
return appendParentTypeArgumentsAndSymbolName(symbol);
10781088
}
10791089

10801090
function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, typeStack?: Type[]) {
@@ -1315,8 +1325,15 @@ module ts {
13151325
}
13161326
}
13171327

1328+
function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) {
1329+
var targetSymbol = getTargetSymbol(symbol);
1330+
if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface) {
1331+
buildDisplayForTypeParametersAndDelimiters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags);
1332+
}
1333+
}
1334+
13181335
function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1319-
buildSymbolDisplay(tp.symbol, writer);
1336+
appendSymbolNameOnly(tp.symbol, writer);
13201337
var constraint = getConstraintOfTypeParameter(tp);
13211338
if (constraint) {
13221339
writeSpace(writer);
@@ -1326,7 +1343,21 @@ module ts {
13261343
}
13271344
}
13281345

1329-
function buildTypeParameterListDisplay(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1346+
function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1347+
if (getDeclarationFlagsFromSymbol(p) & NodeFlags.Rest) {
1348+
writePunctuation(writer, SyntaxKind.DotDotDotToken);
1349+
}
1350+
appendSymbolNameOnly(p, writer);
1351+
if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (<VariableDeclaration>p.valueDeclaration).initializer) {
1352+
writePunctuation(writer, SyntaxKind.QuestionToken);
1353+
}
1354+
writePunctuation(writer, SyntaxKind.ColonToken);
1355+
writeSpace(writer);
1356+
1357+
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack);
1358+
}
1359+
1360+
function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
13301361
if (typeParameters && typeParameters.length) {
13311362
writePunctuation(writer, SyntaxKind.LessThanToken);
13321363
for (var i = 0; i < typeParameters.length; i++) {
@@ -1340,7 +1371,7 @@ module ts {
13401371
}
13411372
}
13421373

1343-
function buildTypeArgumentListDisplay(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1374+
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
13441375
if (typeParameters && typeParameters.length) {
13451376
writePunctuation(writer, SyntaxKind.LessThanToken);
13461377
for (var i = 0; i < typeParameters.length; i++) {
@@ -1354,42 +1385,19 @@ module ts {
13541385
}
13551386
}
13561387

1357-
function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) {
1358-
var targetSymbol = getTargetSymbol(symbol);
1359-
if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface) {
1360-
buildTypeParameterListDisplay(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags);
1361-
}
1362-
}
1363-
1364-
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1365-
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
1366-
// Instantiated signature, write type arguments instead
1367-
buildTypeArgumentListDisplay(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
1368-
}
1369-
else {
1370-
buildTypeParameterListDisplay(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack);
1371-
}
1388+
function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
13721389
writePunctuation(writer, SyntaxKind.OpenParenToken);
1373-
for (var i = 0; i < signature.parameters.length; i++) {
1390+
for (var i = 0; i < parameters.length; i++) {
13741391
if (i > 0) {
13751392
writePunctuation(writer, SyntaxKind.CommaToken);
13761393
writeSpace(writer);
13771394
}
1378-
var p = signature.parameters[i];
1379-
if (getDeclarationFlagsFromSymbol(p) & NodeFlags.Rest) {
1380-
writePunctuation(writer, SyntaxKind.DotDotDotToken);
1381-
}
1382-
buildSymbolDisplay(p, writer);
1383-
if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (<VariableDeclaration>p.valueDeclaration).initializer) {
1384-
writePunctuation(writer, SyntaxKind.QuestionToken);
1385-
}
1386-
writePunctuation(writer, SyntaxKind.ColonToken);
1387-
writeSpace(writer);
1388-
1389-
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack);
1395+
buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack);
13901396
}
1391-
13921397
writePunctuation(writer, SyntaxKind.CloseParenToken);
1398+
}
1399+
1400+
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
13931401
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
13941402
writeSpace(writer);
13951403
writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
@@ -1398,20 +1406,36 @@ module ts {
13981406
writePunctuation(writer, SyntaxKind.ColonToken);
13991407
}
14001408
writeSpace(writer);
1401-
14021409
buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack);
14031410
}
1411+
1412+
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
1413+
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
1414+
// Instantiated signature, write type arguments instead
1415+
// This is achieved by passing in the mapper separately
1416+
buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
1417+
}
1418+
else {
1419+
buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack);
1420+
}
1421+
1422+
buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack);
1423+
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack);
1424+
}
14041425

14051426
return _displayBuilder || (_displayBuilder = {
14061427
symbolToString: symbolToString,
14071428
typeToString: typeToString,
14081429
buildSymbolDisplay: buildSymbolDisplay,
14091430
buildTypeDisplay: buildTypeDisplay,
14101431
buildTypeParameterDisplay: buildTypeParameterDisplay,
1411-
buildTypeParameterListDisplay: buildTypeParameterListDisplay,
1412-
buildTypeArgumentListDisplay: buildTypeArgumentListDisplay,
1432+
buildParameterDisplay: buildParameterDisplay,
1433+
buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters,
1434+
buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters,
1435+
buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters,
14131436
buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol,
1414-
buildSignatureDisplay: buildSignatureDisplay
1437+
buildSignatureDisplay: buildSignatureDisplay,
1438+
buildReturnTypeDisplay: buildReturnTypeDisplay
14151439
});
14161440
}
14171441

src/compiler/parser.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ module ts {
10801080
return isParameter();
10811081
case ParsingContext.TypeArguments:
10821082
case ParsingContext.TupleElementTypes:
1083-
return isType();
1083+
return token === SyntaxKind.CommaToken || isType();
10841084
}
10851085

10861086
Debug.fail("Non-exhaustive case in 'isListElement'.");
@@ -2393,13 +2393,29 @@ module ts {
23932393
function parseTypeArguments(): NodeArray<TypeNode> {
23942394
var typeArgumentListStart = scanner.getTokenPos();
23952395
var errorCountBeforeTypeParameterList = file.syntacticErrors.length;
2396-
var result = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
2396+
// We pass parseSingleTypeArgument instead of parseType as the element parser
2397+
// because parseSingleTypeArgument knows how to parse a missing type argument.
2398+
// This is useful for signature help. parseType has the disadvantage that when
2399+
// it sees a missing type, it changes the LookAheadMode to Error, and the result
2400+
// is a broken binary expression, which breaks signature help.
2401+
var result = parseBracketedList(ParsingContext.TypeArguments, parseSingleTypeArgument, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
23972402
if (!result.length && file.syntacticErrors.length === errorCountBeforeTypeParameterList) {
23982403
grammarErrorAtPos(typeArgumentListStart, scanner.getStartPos() - typeArgumentListStart, Diagnostics.Type_argument_list_cannot_be_empty);
23992404
}
24002405
return result;
24012406
}
24022407

2408+
function parseSingleTypeArgument(): TypeNode {
2409+
if (token === SyntaxKind.CommaToken) {
2410+
var errorStart = scanner.getTokenPos();
2411+
var errorLength = scanner.getTextPos() - errorStart;
2412+
grammarErrorAtPos(errorStart, errorLength, Diagnostics.Type_expected);
2413+
return createNode(SyntaxKind.Missing);
2414+
}
2415+
2416+
return parseType();
2417+
}
2418+
24032419
function parsePrimaryExpression(): Expression {
24042420
switch (token) {
24052421
case SyntaxKind.ThisKeyword:

src/compiler/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,12 @@ module ts {
677677
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
678678
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
679679
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
680+
buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
680681
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
681682
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void;
683+
buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
684+
buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
685+
buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
682686
}
683687

684688
export interface SymbolWriter {

src/services/services.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ module ts {
14601460
}
14611461
}
14621462

1463-
function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
1463+
export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
14641464
writeDisplayParts(displayPartWriter);
14651465
var result = displayPartWriter.displayParts();
14661466
displayPartWriter.clear();

0 commit comments

Comments
 (0)