Various fixes

* create type reference node from type parameters
* expose index signature synthesis
* widen types in helpers
* format unions
* use deep cloning
This commit is contained in:
Arthur Ozga 2017-03-14 14:35:23 -07:00
parent 27fe2df203
commit 2fd3229568
10 changed files with 76 additions and 81 deletions

View file

@ -108,6 +108,7 @@ namespace ts {
getNonNullableType,
createTypeNode,
createTypeParameterDeclarationFromType,
createIndexSignatureFromIndexInfo,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? getSymbolsInScope(location, meaning) : [];
@ -2190,16 +2191,13 @@ namespace ts {
return result;
}
function createTypeParameterDeclarationFromType(type: Type): TypeParameterDeclaration {
function createTypeParameterDeclarationFromType(type: TypeParameter): TypeParameterDeclaration {
if (!(type && type.symbol && type.flags & TypeFlags.TypeParameter)) {
return undefined;
}
const constraint = createTypeNode(getConstraintFromTypeParameter(<TypeParameter>type)) as TypeNode;
const defaultParameter = createTypeNode(getDefaultFromTypeParameter(<TypeParameter>type)) as TypeNode;
if (!type.symbol) {
return undefined;
}
const constraint = createTypeNode(getConstraintFromTypeParameter(type)) as TypeNode;
const defaultParameter = createTypeNode(getDefaultFromTypeParameter(type)) as TypeNode;
const name = symbolToString(type.symbol);
return createTypeParameterDeclaration(name, constraint, defaultParameter);
@ -2212,8 +2210,10 @@ namespace ts {
let checkAlias = true;
let result = createTypeNodeWorker(type);
(<any>result).__type_source = type;
(<any>result).__type_source_str = typeToString(type);
if (result) {
(<any>result).__type_source = type;
(<any>result).__type_source_str = typeToString(type);
}
return result;
function createTypeNodeWorker(type: Type): TypeNode {
@ -2299,7 +2299,16 @@ namespace ts {
return createTypeReferenceNode(name, /*typeParameters*/undefined);
}
if (type.flags & TypeFlags.TypeParameter) {
throw new Error("Type Parameter declarations only handled in other worker.");
const constraint = createTypeNode(getConstraintFromTypeParameter(<TypeParameter>type)) as TypeNode;
const defaultParameter = createTypeNode(getDefaultFromTypeParameter(<TypeParameter>type)) as TypeNode;
if(constraint || defaultParameter) {
// Type parameters in type position can't have constraints or defaults.
encounteredError = true;
return undefined;
}
// TODO: get qualified name when necessary instead of string.
const name = symbolToString(type.symbol);
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
// accessible type aliasSymbol
@ -2312,7 +2321,7 @@ namespace ts {
checkAlias = false;
if (type.flags & TypeFlags.Union) {
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, mapToTypeNodeArray((type as UnionType).types));
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, mapToTypeNodeArray(formatUnionTypes((<UnionType>type).types)));
}
if (type.flags & TypeFlags.Intersection) {
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
@ -2467,34 +2476,29 @@ namespace ts {
});
return typeElements.length ? typeElements : undefined;
}
function createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind) {
const stringTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
const name = (indexInfo.declaration && indexInfo.declaration.name && getTextOfPropertyName(indexInfo.declaration.name)) || "x";
const indexingParameter = createParameter(
/*decorators*/ undefined
, /*modifiers*/ undefined
, /*dotDotDotToken*/ undefined
, name
, /*questionToken*/ undefined
, stringTypeNode
, /*initializer*/ undefined);
const typeNode = createTypeNode(indexInfo.type);
return createIndexSignatureDeclaration(
[indexingParameter]
, typeNode
, /*decoarators*/ undefined
, indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
}
// /** Note that mapToTypeNodeArray(undefined) === undefined. */
// function mapToTypeParameterArray(types: Type[]): NodeArray<TypeNode> {
// return asNodeArray(types && types.map(createTypeParameterDeclarationFromType) as TypeNode[]);
// }
}
}
function createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration {
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
const name = getNameFromIndexInfo(indexInfo);
const indexingParameter = createParameter(
/*decorators*/ undefined
, /*modifiers*/ undefined
, /*dotDotDotToken*/ undefined
, name
, /*questionToken*/ undefined
, indexerTypeNode
, /*initializer*/ undefined);
const typeNode = createTypeNode(indexInfo.type);
return createIndexSignatureDeclaration(
[indexingParameter]
, typeNode
, /*decorators*/ undefined
, indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
}
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
const writer = getSingleLineStringWriter();
getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);

View file

@ -2471,6 +2471,8 @@ namespace ts {
createTypeNode(type: Type): TypeNode;
/** Note that the resulting type node cannot be checked. */
createTypeParameterDeclarationFromType(type: Type): TypeParameterDeclaration;
/** Note that the resulting type node cannot be checked. */
createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolAtLocation(node: Node): Symbol;

View file

@ -524,6 +524,10 @@ namespace ts {
export function declarationNameToString(name: DeclarationName) {
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
}
export function getNameFromIndexInfo(info: IndexInfo) {
return info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : undefined;
}
export function getTextOfPropertyName(name: PropertyName): string {
switch (name.kind) {

View file

@ -53,18 +53,7 @@ namespace ts.codefix {
if (!indexInfoOfKind) {
return undefined;
}
const typeNode = checker.createTypeNode(indexInfoOfKind.type);
const newIndexSignatureDeclaration = createIndexSignatureDeclaration(
[createParameter(
/*decorators*/undefined
, /*modifiers*/ undefined
, /*dotDotDotToken*/ undefined
, getNameFromIndexInfo(indexInfoOfKind)
, /*questionToken*/ undefined
, kind === IndexKind.String ? createKeywordTypeNode(SyntaxKind.StringKeyword) : createKeywordTypeNode(SyntaxKind.NumberKeyword))]
, typeNode
, /*decorators*/undefined
, /*modifiers*/ undefined);
const newIndexSignatureDeclaration = checker.createIndexSignatureFromIndexInfo(indexInfoOfKind, kind);
newNodes.push(newIndexSignatureDeclaration);
}

View file

@ -52,10 +52,10 @@ namespace ts.codefix {
const declaration = declarations[0] as Declaration;
// TODO: get name as identifier or computer property name, etc.
const name = declaration.name ? declaration.name.getText() : undefined;
const name = declaration.name ? getSynthesizedDeepClone(declaration.name) as PropertyName : undefined;
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
const modifiers = visibilityModifier ? [visibilityModifier] : undefined;
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
@ -94,7 +94,7 @@ namespace ts.codefix {
const newTypeParameters = signature.typeParameters && signature.typeParameters.map(checker.createTypeParameterDeclarationFromType);
const newParameterNodes = signature.getParameters().map(symbol => createParameterDeclarationFromSymbol(symbol, enclosingDeclaration, checker));
const returnType = checker.createTypeNode(checker.getReturnTypeOfSignature(signature));
const returnType = checker.createTypeNode(checker.getWidenedType(checker.getReturnTypeOfSignature(signature)));
return createStubbedMethod(modifiers, name, newTypeParameters, newParameterNodes, returnType);
}
@ -121,7 +121,7 @@ namespace ts.codefix {
let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
const newTypeParameters = signature.typeParameters && signature.typeParameters.map(checker.createTypeParameterDeclarationFromType);
const newParameterNodes = signature.getParameters().map(symbol => createParameterDeclarationFromSymbol(symbol, enclosingDeclaration, checker));
const returnType = checker.createTypeNode(signature.resolvedReturnType);
const returnType = checker.createTypeNode(checker.getWidenedType(checker.getReturnTypeOfSignature(signature)));
signatureDeclarations.push(createStubbedMethod(modifiers, name, newTypeParameters, newParameterNodes, returnType));
}
else {
@ -135,7 +135,7 @@ namespace ts.codefix {
}
}
function createMethodImplementingSignatures(signatures: Signature[], name: string, modifiers: Modifier[] | undefined): MethodDeclaration {
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, modifiers: Modifier[] | undefined): MethodDeclaration {
Debug.assert(signatures && signatures.length > 0);
let maxNonRestArgs = -1;
@ -189,7 +189,7 @@ namespace ts.codefix {
, /*returnType*/ undefined);
}
export function createStubbedMethod(modifiers: Modifier[], name: string, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
return createMethod(
/*decorators*/undefined
, modifiers
@ -223,7 +223,7 @@ namespace ts.codefix {
function createParameterDeclarationFromSymbol(parameterSymbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker) {
const parameterDeclaration = parameterSymbol.getDeclarations()[0] as ParameterDeclaration;
const parameterType = checker.getTypeOfSymbolAtLocation(parameterSymbol, enclosingDeclaration);
const parameterType = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(parameterSymbol, enclosingDeclaration));
const parameterTypeNode = checker.createTypeNode(parameterType);
// TODO: deep cloning of decorators/any node.
const parameterNode = createParameter(
@ -236,8 +236,4 @@ namespace ts.codefix {
, /*initializer*/ undefined);
return parameterNode;
}
export function getNameFromIndexInfo(info: IndexInfo) {
return info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x"
}
}

View file

@ -1,18 +0,0 @@
/// <reference path='fourslash.ts' />
//// abstract class C1 {
////
//// }
////
//// abstract class C2 {
//// abstract f1<T extends number>();
//// }
////
//// interface I1 extends C1, C2 {}
////
//// class C3 implements I1 {[| |]}
verify.rangeAfterCodeFix(`f1<T extends number>(){
throw new Error("Method not implemented.");
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
// abstract class C1 {
//
// }
//
// abstract class C2 {
// abstract f1<T extends number>();
// }
//
// interface I1 extends C1, C2 {}
//
// class C3 implements I1 {[| |]}
verify.rangeAfterCodeFix(`f1<T extends number>(){
throw new Error("Method not implemented.");
}
`);

View file

@ -7,8 +7,8 @@
//// y: number;
//// }
////
//// class C implements I1,I2 {[| |]
//// y: number;
//// class C implements I1,I2 {[|
//// |]y: number;
//// }
verify.rangeAfterCodeFix(`

View file

@ -7,9 +7,9 @@
//// y: number;
//// }
////
//// class C implements I1,I2 {[| |]
//// x: number;
//// |]}
//// class C implements I1,I2 {[|
//// |]x: number;
//// }
verify.rangeAfterCodeFix(`
y: number;