Fix generic symbol display information

This commit is contained in:
Sheetal Nandi
2014-10-06 12:29:49 -07:00
parent 61994a7e62
commit be051f02b5
9 changed files with 109 additions and 61 deletions

View File

@@ -103,6 +103,7 @@ module ts {
getSignatureFromDeclaration: getSignatureFromDeclaration,
writeSignature: writeSignature,
writeTypeParameter: writeTypeParameter,
writeTypeParametersOfSymbol: writeTypeParametersOfSymbol,
isImplementationOfOverload: isImplementationOfOverload
};
@@ -966,18 +967,26 @@ module ts {
// Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
// Meaning needs to be specified if the enclosing declaration is given
function writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void {
var previouslyWrittenSymbol: Symbol;
function writeSymbolName(symbol: Symbol): void {
if (previouslyWrittenSymbol) {
// Write type arguments of instantiated class/interface here
if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) {
if (symbol.flags & SymbolFlags.Instantiated) {
writeTypeArguments(getTypeParametersOfClassOrInterface(previouslyWrittenSymbol),
(<TransientSymbol>symbol).mapper, writer, enclosingDeclaration);
}
else {
writeTypeParametersOfSymbol(previouslyWrittenSymbol, writer, enclosingDeclaration);
}
}
writePunctuation(writer, SyntaxKind.DotToken);
}
previouslyWrittenSymbol = symbol;
if (symbol.declarations && symbol.declarations.length > 0) {
var declaration = symbol.declarations[0];
if (declaration.name) {
writer.writeSymbol(identifierToString(declaration.name), symbol);
if (flags & SymbolFormatFlags.WriteTypeParametersOfClassOrInterface) {
var rootSymbol = getRootSymbol(symbol);
if (rootSymbol.flags & SymbolFlags.Class || rootSymbol.flags & SymbolFlags.Interface) {
writeTypeParameters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaration);
}
}
return;
}
}
@@ -985,16 +994,14 @@ module ts {
writer.writeSymbol(symbol.name, symbol);
}
// Let the writer know we just wrote out a symbol. The declarationemitter writer uses
// this to determine if an import it has previously seen (and not writter out) needs
// Let the writer know we just wrote out a symbol. The declaration emitter writer uses
// this to determine if an import it has previously seen (and not writer out) needs
// to be written to the file once the walk of the tree is complete.
//
// NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree
// up front (for example, during checking) could determien if we need to emit the imports
// up front (for example, during checking) could determine if we need to emit the imports
// and we could then access that data during declaration emit.
writer.trackSymbol(symbol, enclosingDeclaration, meaning);
var needsDot = false;
function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void {
if (symbol) {
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning);
@@ -1010,17 +1017,12 @@ module ts {
if (accessibleSymbolChain) {
for (var i = 0, n = accessibleSymbolChain.length; i < n; i++) {
if (needsDot) {
writePunctuation(writer, SyntaxKind.DotToken);
}
writeSymbolName(accessibleSymbolChain[i]);
needsDot = true;
}
}
else {
// If we didn't find accessible symbol chain for this symbol, break if this is external module
if (!needsDot && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
if (!previouslyWrittenSymbol && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
return;
}
@@ -1029,12 +1031,7 @@ module ts {
return;
}
if (needsDot) {
writePunctuation(writer, SyntaxKind.DotToken);
}
writeSymbolName(symbol);
needsDot = true;
}
}
}
@@ -1303,8 +1300,35 @@ module ts {
}
}
function writeTypeArguments(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
if (typeParameters && typeParameters.length) {
writePunctuation(writer, SyntaxKind.LessThanToken);
for (var i = 0; i < typeParameters.length; i++) {
if (i > 0) {
writePunctuation(writer, SyntaxKind.CommaToken);
writeSpace(writer);
}
writeType(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.WriteArrowStyleSignature);
}
writePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
function writeTypeParametersOfSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) {
var rootSymbol = getRootSymbol(symbol);
if (rootSymbol.flags & SymbolFlags.Class || rootSymbol.flags & SymbolFlags.Interface) {
writeTypeParameters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags);
}
}
function writeSignature(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
writeTypeParameters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack);
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
// Instantiated signature, write type arguments instead
writeTypeArguments(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
}
else {
writeTypeParameters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack);
}
writePunctuation(writer, SyntaxKind.OpenParenToken);
for (var i = 0; i < signature.parameters.length; i++) {
if (i > 0) {

View File

@@ -654,6 +654,7 @@ module ts {
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature;
writeSignature(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
writeTypeParameter(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
writeTypeParametersOfSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void;
isImplementationOfOverload(node: FunctionDeclaration): boolean;
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
@@ -684,11 +685,15 @@ module ts {
NoTruncation = 0x00000004, // Don't truncate typeToString result
WriteArrowStyleSignature= 0x00000008, // Write arrow style signature
WriteOwnNameForAnyLike = 0x00000010, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc)
WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature
}
export enum SymbolFormatFlags {
None = 0x00000000,
WriteTypeParametersOfClassOrInterface = 0x00000001, // Write c<T> instead of just writing symbol name c of generic class
None = 0x00000000,
WriteTypeParametersOrArguments = 0x00000001, // Write symbols's type argument if it is instantiated symbol
// eg. class C<T> { p: T } <-- Show p as C<T>.p here
// var a: C<number>;
// var p = a.p; <--- Here p is property of C<number> so show it as C<number>.p instead of just C.p
}
export enum SymbolAccessibility {

View File

@@ -2726,7 +2726,7 @@ module ts {
var useConstructSignatures = callExpression.kind === SyntaxKind.NewExpression || callExpression.func.kind === SyntaxKind.SuperKeyword;
var allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures();
if (contains(allSignatures, signature)) {
if (contains(allSignatures, signature.target || signature)) {
// Write it as method/function/constructor as: (constructor) a(....)
if (symbolKind === ScriptElementKind.memberVariableElement || symbolFlags & SymbolFlags.Variable || symbolFlags & SymbolFlags.Class) {
if (useConstructSignatures) {
@@ -2793,13 +2793,15 @@ module ts {
if (symbolFlags & SymbolFlags.Class && !hasAddedSymbolInfo) {
displayParts.push(keywordPart(SyntaxKind.ClassKeyword));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
writeTypeParametersOfSymbol(symbol, sourceFile);
}
if (symbolFlags & SymbolFlags.Interface) {
addNewLineIfDisplayPartsExist();
displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
writeTypeParametersOfSymbol(symbol, sourceFile);
}
if (symbolFlags & SymbolFlags.Enum) {
addNewLineIfDisplayPartsExist();
@@ -2825,7 +2827,8 @@ module ts {
displayParts.push(spacePart());
if (symbol.parent) {
// Class/Interface type parameter
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol.parent, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface))
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol.parent, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments))
writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration);
}
else {
// Method/function type parameter
@@ -2835,9 +2838,9 @@ module ts {
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
displayParts.push(spacePart());
} else if (signatureDeclaration.kind !== SyntaxKind.CallSignature) {
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, signatureDeclaration.symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface))
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, signatureDeclaration.symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments))
}
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.NoTruncation));
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.NoTruncation | TypeFormatFlags.WriteTypeArgumentsOfSignature));
}
}
if (symbolFlags & SymbolFlags.EnumMember) {
@@ -2910,12 +2913,12 @@ module ts {
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
displayParts.push(spacePart());
// Write type parameters of class/Interface if it is property/method of the generic class/interface
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
}
}
function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[]) {
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, TypeFormatFlags.NoTruncation));
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, TypeFormatFlags.NoTruncation | TypeFormatFlags.WriteTypeArgumentsOfSignature));
if (allSignatures.length > 1) {
displayParts.push(spacePart());
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
@@ -2931,6 +2934,13 @@ module ts {
}
documentation = signature.getDocumentationComment();
}
function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) {
var typeParameterParts = mapToDisplayParts(writer => {
typeResolver.writeTypeParametersOfSymbol(symbol, writer, enclosingDeclaration, TypeFormatFlags.NoTruncation);
});
displayParts.push.apply(displayParts, typeParameterParts);
}
}
function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo {