Format typeparameters information

This commit is contained in:
Sheetal Nandi
2014-09-30 16:53:10 -07:00
parent 010b9b663e
commit 4781224d86
12 changed files with 156 additions and 93 deletions

View File

@@ -102,6 +102,7 @@ module ts {
isValidPropertyAccess: isValidPropertyAccess,
getSignatureFromDeclaration: getSignatureFromDeclaration,
writeSignature: writeSignature,
writeTypeParameter: writeTypeParameter,
isImplementationOfOverload: isImplementationOfOverload
};
@@ -964,12 +965,19 @@ 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): void {
function writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void {
function writeSymbolName(symbol: Symbol): void {
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;
}
}
@@ -1268,26 +1276,33 @@ module ts {
}
}
function writeSignature(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
if (signature.typeParameters) {
function writeTypeParameter(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
writeSymbol(tp.symbol, writer);
var constraint = getConstraintOfTypeParameter(tp);
if (constraint) {
writeSpace(writer);
writeKeyword(writer, SyntaxKind.ExtendsKeyword);
writeSpace(writer);
writeType(constraint, writer, enclosingDeclaration, flags, typeStack);
}
}
function writeTypeParameters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
if (typeParameters) {
writePunctuation(writer, SyntaxKind.LessThanToken);
for (var i = 0; i < signature.typeParameters.length; i++) {
for (var i = 0; i < typeParameters.length; i++) {
if (i > 0) {
writePunctuation(writer, SyntaxKind.CommaToken);
writeSpace(writer);
}
var tp = signature.typeParameters[i];
writeSymbol(tp.symbol, writer);
var constraint = getConstraintOfTypeParameter(tp);
if (constraint) {
writeSpace(writer);
writeKeyword(writer, SyntaxKind.ExtendsKeyword);
writeSpace(writer);
writeType(constraint, writer, enclosingDeclaration, flags, typeStack);
}
writeTypeParameter(typeParameters[i], writer, enclosingDeclaration, flags, typeStack);
}
writePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
function writeSignature(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
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

@@ -645,7 +645,7 @@ module ts {
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
writeType(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
getFullyQualifiedName(symbol: Symbol): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
getRootSymbol(symbol: Symbol): Symbol;
@@ -653,6 +653,7 @@ module ts {
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature;
writeSignature(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
writeTypeParameter(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: 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,6 +685,11 @@ module ts {
WriteArrowStyleSignature= 0x00000008, // Write arrow style signature
}
export enum SymbolFormatFlags {
None = 0x00000000,
WriteTypeParametersOfClassOrInterface = 0x00000001, // Write c<T> instead of just writing symbol name c of generic class
}
export enum SymbolAccessibility {
Accessible,
NotAccessible,

View File

@@ -1405,29 +1405,30 @@ module ts {
}
}
function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
var displayPartWriter = getDisplayPartWriter();
writeDisplayParts(displayPartWriter);
var result = displayPartWriter.displayParts();
releaseDisplayPartWriter(displayPartWriter);
return result;
}
export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
var displayPartWriter = getDisplayPartWriter();
typechecker.writeType(type, displayPartWriter, enclosingDeclaration, flags);
var result = displayPartWriter.displayParts();
releaseDisplayPartWriter(displayPartWriter);
return result;
return mapToDisplayParts(writer => {
typechecker.writeType(type, writer, enclosingDeclaration, flags);
});
}
export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[] {
var displayPartWriter = getDisplayPartWriter();
typeChecker.writeSymbol(symbol, displayPartWriter, enclosingDeclaration, meaning);
var result = displayPartWriter.displayParts();
releaseDisplayPartWriter(displayPartWriter);
return result;
export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
return mapToDisplayParts(writer => {
typeChecker.writeSymbol(symbol, writer, enclosingDeclaration, meaning, flags);
});
}
function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
var displayPartWriter = getDisplayPartWriter();
typechecker.writeSignature(signature, displayPartWriter, enclosingDeclaration, flags);
var result = displayPartWriter.displayParts();
releaseDisplayPartWriter(displayPartWriter);
return result;
function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[]{
return mapToDisplayParts(writer => {
typechecker.writeSignature(signature, writer, enclosingDeclaration, flags);
});
}
export function getDefaultCompilerOptions(): CompilerOptions {
@@ -2792,13 +2793,13 @@ module ts {
if (symbolFlags & SymbolFlags.Class && !hasAddedSymbolInfo) {
displayParts.push(keywordPart(SyntaxKind.ClassKeyword));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface));
}
if (symbolFlags & SymbolFlags.Interface) {
addNewLineIfDisplayPartsExist();
displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface));
}
if (symbolFlags & SymbolFlags.Enum) {
addNewLineIfDisplayPartsExist();
@@ -2819,6 +2820,25 @@ module ts {
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration));
displayParts.push(spacePart());
displayParts.push(keywordPart(SyntaxKind.InKeyword));
displayParts.push(spacePart());
if (symbol.parent) {
// Class/Interface type parameter
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol.parent, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOfClassOrInterface))
}
else {
// Method/function type parameter
var signatureDeclaration = <SignatureDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent;
var signature = typeResolver.getSignatureFromDeclaration(signatureDeclaration);
if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) {
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, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.NoTruncation));
}
}
if (symbolFlags & SymbolFlags.EnumMember) {
addPrefixForAnyFunctionOrVar(symbol, "enum member");
@@ -2848,7 +2868,16 @@ module ts {
symbolFlags & SymbolFlags.Variable) {
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, type, enclosingDeclaration, TypeFormatFlags.NoTruncation));
// If the type is type parameter, format it specially
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) {
var typeParameterParts = mapToDisplayParts(writer => {
typeResolver.writeTypeParameter(<TypeParameter>type, writer, enclosingDeclaration, TypeFormatFlags.NoTruncation);
});
displayParts.push.apply(displayParts, typeParameterParts);
}
else {
displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, type, enclosingDeclaration, TypeFormatFlags.NoTruncation));
}
}
else if (symbolFlags & SymbolFlags.Function ||
symbolFlags & SymbolFlags.Method ||
@@ -2880,9 +2909,8 @@ module ts {
displayParts.push(textPart(symbolKind));
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
displayParts.push(spacePart());
//if (symbol.declarations && symbol.declarations.length) {
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
//}
// 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));
}
}

View File

@@ -6,7 +6,6 @@
////a./**/
goTo.marker();
// TODO. show as Array<number> or Array<T>.length instead
verify.memberListContains('length', "(property) Array.length: number", /*docComments*/ undefined, /*kind*/ "property");
verify.memberListContains('toString', "(method) Array.toString(): string", /*docComments*/ undefined, /*kind*/ "method");
verify.memberListContains('length', "(property) Array<T>.length: number", /*docComments*/ undefined, /*kind*/ "property");
verify.memberListContains('toString', "(method) Array<T>.toString(): string", /*docComments*/ undefined, /*kind*/ "method");

View File

@@ -20,5 +20,5 @@
goTo.marker();
verify.completionListContains('watch', '(property) iBaseScope.watch: () => void');
verify.completionListContains('moveUp', '(property) iMover.moveUp: () => void');
//verify.completionListContains('family', '(property) iScope<number>.family: number');
// TODO
debugger;
verify.completionListContains('family', '(property) iScope<TModel>.family: number');

View File

@@ -4,6 +4,4 @@
////function foo4<T extends Date>(test: any): any { return null; }
goTo.marker();
// TODO: formatting type parameter with extends info
//verify.quickInfoIs('parameter) test: T extends Date');
verify.quickInfoIs('(parameter) test: T');
verify.quickInfoIs('(parameter) test: T extends Date');

View File

@@ -0,0 +1,48 @@
/// <reference path='fourslash.ts' />
////class Con/*1*/tainer<T> {
//// x: T;
////}
////interface IList</*2*/T> {
//// getItem(i: number): /*3*/T;
////}
////class List</*4*/T extends IList<number>> implements IList<T> {
//// private __it/*6*/em: /*5*/T[];
//// public get/*7*/Item(i: number) {
//// return this.__item[i];
//// }
//// public /*8*/method</*9*/S extends IList<T>>(s: S, p: /*10*/T[]) {
//// return s;
//// }
////}
////function foo4</*11*/T extends Date>(test: T): T;
////function foo4</*12*/S extends string>(test: S): S;
////function foo4(test: any): any;
////function foo4</*13*/T extends Date>(test: any): any { return null; }
goTo.marker("1");
verify.quickInfoIs("class Container<T>", undefined);
goTo.marker("2");
verify.quickInfoIs("(type parameter) T in IList<T>", undefined);
goTo.marker("3");
verify.quickInfoIs("(type parameter) T in IList<T>", undefined);
goTo.marker("4");
verify.quickInfoIs("(type parameter) T in List<T extends IList<number>>", undefined);
goTo.marker("5");
verify.quickInfoIs("(type parameter) T in List<T extends IList<number>>", undefined);
goTo.marker("6");
verify.quickInfoIs("(property) List<T extends IList<number>>.__item: T[]", undefined);
goTo.marker("7");
verify.quickInfoIs("(method) List<T extends IList<number>>.getItem(i: number): T", undefined);
goTo.marker("8");
verify.quickInfoIs("(method) List<T extends IList<number>>.method<S extends IList<T>>(s: S, p: T[]): S", undefined);
goTo.marker("9");
verify.quickInfoIs("(type parameter) S in List<T extends IList<number>>.method<S extends IList<T>>(s: S, p: T[]): S", undefined);
goTo.marker("10");
verify.quickInfoIs("(type parameter) T in List<T extends IList<number>>", undefined);
goTo.marker("11");
verify.quickInfoIs("(type parameter) T in foo4<T extends Date>(test: T): T", undefined);
goTo.marker("12");
verify.quickInfoIs("(type parameter) S in foo4<S extends string>(test: S): S", undefined);
goTo.marker("13");
verify.quickInfoIs("(type parameter) T in foo4<T extends Date>(test: any): any", undefined);

View File

@@ -5,4 +5,4 @@
////}
goTo.marker();
verify.quickInfoIs('Container<T>', null, 'Container<T>');
verify.quickInfoIs('class Container<T>', null);

View File

@@ -0,0 +1,9 @@
/// <reference path='fourslash.ts'/>
////interface Fo/*1*/o<T/*2*/T extends Date> {}
goTo.marker('1');
verify.quickInfoIs('interface Foo<TT extends Date>', null);
goTo.marker('2');
verify.quickInfoIs('(type parameter) TT in Foo<TT extends Date>', null);

View File

@@ -9,20 +9,20 @@
//// }
//// var b: B<string>;
//// var r3 = b.foo; // number
//// var r/*2*/4 = b.ba/*1*/r; // string
//// var r/*2*/4 = b.b/*1*/ar; // string
////}
diagnostics.setEditValidation(IncrementalEditValidation.None);
goTo.marker('1');
verify.quickInfoIs("string", undefined, "MM.B<T>.bar", "property");
verify.quickInfoIs("(property) B<T>.bar: string", undefined);
edit.deleteAtCaret(1);
edit.insert('z');
verify.quickInfoIs("any");
verify.not.quickInfoExists();
verify.numberOfErrorsInCurrentFile(1);
edit.backspace(1);
edit.insert('r');
verify.quickInfoIs("string", undefined, "MM.B<T>.bar", "property");
edit.insert('a');
verify.quickInfoIs("(property) B<T>.bar: string", undefined);
goTo.marker('2');
verify.quickInfoIs("string", undefined, "r4", "var");
verify.quickInfoIs("(var) r4: string", undefined);
verify.numberOfErrorsInCurrentFile(0);

View File

@@ -1,31 +0,0 @@
/// <reference path='fourslash.ts' />
////class Con/*1*/tainer<T> {
//// x: T;
////}
////interface IList</*2*/T> {
//// getItem(i: number): /*3*/T;
////}
////class List</*4*/T extends IList<T>> implements IList<T> {
//// private __it/*6*/em: /*5*/T[];
//// public get/*7*/Item(i: number) {
//// return this.__item[i];
//// }
////}
goTo.marker("1");
verify.quickInfoIs(undefined, undefined, "Container<T>", "class");
goTo.marker("2");
verify.quickInfoIs(undefined, undefined, "T in IList<T>", "type parameter");
goTo.marker("3");
verify.quickInfoIs(undefined, undefined, "T in IList<T>", "type parameter");
goTo.marker("4");
verify.quickInfoIs(undefined, undefined, "T in List<T extends IList<T>>", "type parameter");
goTo.marker("5");
verify.quickInfoIs(undefined, undefined, "T in List<T extends IList<T>>", "type parameter");
goTo.marker("6");
verify.quickInfoIs(undefined, undefined, "List<T extends IList<T>>.__item", "property");
goTo.marker("7");
verify.quickInfoIs(undefined, undefined, "List<T extends IList<T>>.getItem", "method");

View File

@@ -1,9 +0,0 @@
/// <reference path='fourslash.ts'/>
////interface Fo/*1*/o<T/*2*/T extends Date> {}
goTo.marker('1');
verify.quickInfoIs('Foo<TT extends Date>', null, 'Foo<TT extends Date>')
goTo.marker('2');
verify.quickInfoIs('TT extends Date', null, 'TT in Foo<TT extends Date>')