signatures, parameter, literals, anyonymous types

This commit is contained in:
Arthur Ozga
2017-03-16 16:41:26 -07:00
parent 451b2d648f
commit 0fa4f112a3
5 changed files with 181 additions and 257 deletions
+103 -180
View File
@@ -109,6 +109,7 @@ namespace ts {
createTypeNode,
createTypeParameterDeclarationFromType,
createIndexSignatureFromIndexInfo,
createParameterDeclarationFromSymbol,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? getSymbolsInScope(location, meaning) : [];
@@ -2203,6 +2204,45 @@ namespace ts {
return createTypeParameterDeclaration(name, constraint, defaultParameter);
}
// TODO: enclosing declaration appears to be unused in getTypeOfSymbolAtLocation
function createParameterDeclarationFromSymbol(parameterSymbol: Symbol): ParameterDeclaration {
const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration;
const parameterType = getTypeOfSymbol(parameterSymbol);
const parameterTypeNode = checker.createTypeNode(parameterType);
// TODO: clone binding names correctly.
// TODO: copy initialzer in a way that checks whether all symbols used in expression are accessible here, and qualify them appropriately.
const parameterNode = createParameter(
parameterDeclaration.decorators && parameterDeclaration.decorators.map(getSynthesizedDeepClone)
, parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedDeepClone)
, parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken)
, getSynthesizedDeepClone(parameterDeclaration.name)
, parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken)
, parameterTypeNode
, /*initializer*/ undefined);
return parameterNode;
}
/* @internal */
type SignatureParts = {
typeParameters: TypeParameterDeclaration[] | undefined;
parameters: ParameterDeclaration[];
type: TypeNode;
}
// TODO: expose this, remove copy from helper, possibly don't expose createParameter/TypeParameter?
function createSignatureParts(signature: Signature): SignatureParts {
return {
typeParameters: signature.typeParameters && signature.typeParameters.map(createTypeParameterDeclarationFromType),
parameters: signature.parameters.map(createParameterDeclarationFromSymbol),
type: createTypeNodeExceptAny(getReturnTypeOfSignature(signature))
}
function createTypeNodeExceptAny(type: Type): TypeNode | undefined {
const typeNode = createTypeNode(type);
return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined;
}
}
function createTypeNode(type: Type): TypeNode {
let undefinedArgumentIsError = true;
let encounteredError = false;
@@ -2322,22 +2362,6 @@ namespace ts {
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
}
if (objectFlags & ObjectFlags.Mapped) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// TODO: does typeParameter have the same constraint or do we need to overwrite it somehow?
const typeParameter = getTypeParameterFromMappedType(<MappedType>type);
// const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
const typeParameterNode = createTypeParameterDeclarationFromType(typeParameter);
const templateTypeNode = createTypeNode(getTemplateTypeFromMappedType(<MappedType>type));
const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
// TODO: test.
return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
}
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// The type is an object literal type.
@@ -2371,57 +2395,25 @@ namespace ts {
return asNodeArray(types && types.map(createTypeNodeWorker) as TypeNode[]);
}
/******** START COPY *********/
// function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
// const globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike;
// let inObjectTypeLiteral = false;
// return writeType(type, globalFlags);
// function writeType(type: Type, flags: TypeFormatFlags) {
// // const nextFlags = flags & ~TypeFormatFlags.InTypeAlias;
// // // Write undefined/null type as any
// // if (type.flags & TypeFlags.Intrinsic) {
// // // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving
// // writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type)
// // ? "any"
// // : (<IntrinsicType>type).intrinsicName);
// // }
// // else if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
// // if (inObjectTypeLiteral) {
// // writer.reportInaccessibleThisError();
// // }
// // writer.writeKeyword("this");
// // }
// else if (getObjectFlags(type) & ObjectFlags.Reference) {
// writeTypeReference(<TypeReference>type, nextFlags);
// }
// else if (type.flags & TypeFlags.EnumLiteral) {
// buildSymbolDisplay(getParentOfSymbol(type.symbol), writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
// writePunctuation(writer, SyntaxKind.DotToken);
// appendSymbolNameOnly(type.symbol, writer);
// }
// else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) {
// // The specified symbol flags need to be reinterpreted as type flags
// buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
// }
// else if (!(flags & TypeFormatFlags.InTypeAlias) && type.aliasSymbol &&
// isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
// const typeArguments = type.aliasTypeArguments;
// writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, length(typeArguments), nextFlags);
// }
// else if (type.flags & TypeFlags.UnionOrIntersection) {
// writeUnionOrIntersectionType(<UnionOrIntersectionType>type, nextFlags);
// }
// else if (getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
// writeAnonymousType(<ObjectType>type, nextFlags);
// }
// TODO: implement when this is testable.
// else if (type.flags & TypeFlags.StringOrNumberLiteral) {
// writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
// }
// }
/******** END COPY *********/
function createMappedTypeNodeFromType(type: MappedType) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// TODO: does typeParameter have the same constraint or do we need to overwrite it somehow?
const typeParameter = getTypeParameterFromMappedType(<MappedType>type);
// const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
const typeParameterNode = createTypeParameterDeclarationFromType(typeParameter);
const templateTypeNode = createTypeNode(getTemplateTypeFromMappedType(<MappedType>type));
const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
// TODO: test.
return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
}
function createAnonymousTypeNode(type: ObjectType): TypeNode {
const symbol = type.symbol;
@@ -2439,7 +2431,7 @@ namespace ts {
const typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags
const entityName = getEntityNameFromSymbol(typeAlias, enclosingDeclaration);
const entityName = createNameFromSymbol(typeAlias, enclosingDeclaration);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
}
else {
@@ -2453,14 +2445,14 @@ namespace ts {
symbolStack = [];
}
symbolStack.push(symbol);
let result = createTypeLiteralNodeFromType(type);
let result = createTypeNodeFromObjectType(type);
symbolStack.pop();
return result;
}
}
else {
// Anonymous types with no symbol are never circular
return createTypeLiteralNodeFromType(type);
return createTypeNodeFromObjectType(type);
}
function shouldWriteTypeOfFunctionSymbol() {
@@ -2477,103 +2469,48 @@ namespace ts {
}
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
if (type.objectFlags & ObjectFlags.Mapped) {
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
writeMappedType(<MappedType>type);
return;
return createMappedTypeNodeFromType(<MappedType>type);
}
}
const resolved = resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
writePunctuation(writer, SyntaxKind.OpenBraceToken);
writePunctuation(writer, SyntaxKind.CloseBraceToken);
return;
return createTypeLiteralNode(/*members*/ undefined);
}
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags);
if (parenthesizeSignature) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
if (parenthesizeSignature) {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
const signature = resolved.callSignatures[0];
const signatureParts = createSignatureParts(signature);
return createSignatureDeclaration<FunctionTypeNode>(SyntaxKind.FunctionType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
}
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
writeKeyword(writer, SyntaxKind.NewKeyword);
writeSpace(writer);
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
const signature = resolved.constructSignatures[0];
const signatureParts = createSignatureParts(signature);
return createSignatureDeclaration<ConstructorTypeNode>(SyntaxKind.ConstructorType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
}
}
const saveInObjectTypeLiteral = inObjectTypeLiteral;
inObjectTypeLiteral = true;
writePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.writeLine();
writer.increaseIndent();
writeObjectLiteralType(resolved);
writer.decreaseIndent();
writePunctuation(writer, SyntaxKind.CloseBraceToken);
const members = createTypeNodesFromResolvedType(resolved);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
function writeObjectLiteralType(resolved: ResolvedType) {
for (const signature of resolved.callSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
for (const signature of resolved.constructSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, SignatureKind.Construct, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
buildIndexSignatureDisplay(resolved.stringIndexInfo, writer, IndexKind.String, enclosingDeclaration, globalFlags, symbolStack);
buildIndexSignatureDisplay(resolved.numberIndexInfo, writer, IndexKind.Number, enclosingDeclaration, globalFlags, symbolStack);
for (const p of resolved.properties) {
const t = getTypeOfSymbol(p);
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
const signatures = getSignaturesOfType(t, SignatureKind.Call);
for (const signature of signatures) {
writePropertyWithModifiers(p);
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
else {
writePropertyWithModifiers(p);
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
writeType(t, TypeFormatFlags.None);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
return createTypeLiteralNode(members);
}
function createTypeQueryNodeFromType(type: Type) {
const symbol = type.symbol;
if (symbol) {
// TODO: get entity name instead.
const entityName = createIdentifier(symbolToString(symbol));
const entityName = createNameFromSymbol(symbol);
return createTypeQueryNode(entityName);
}
}
function getEntityNameFromSymbol(symbol: Symbol, enclosingDeclaration: Node): EntityName {
function createNameFromSymbol(symbol: Symbol): EntityName {
symbol; enclosingDeclaration;
// TODO: actually implement this
return createIdentifier(symbolToString(symbol, enclosingDeclaration));
@@ -2636,67 +2573,53 @@ namespace ts {
}
}
function createTypeLiteralNodeFromType(type: ObjectType) {
const resolvedType = resolveStructuredTypeMembers(type);
const newMembers = createTypeNodesFromResolvedType(resolvedType);
return createTypeLiteralNode(newMembers);
}
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
const typeElements: TypeElement[] = [];
for(const signature of resolvedType.callSignatures) {
signature;
throw new Error("call signatures not implemented");
for (const signature of resolvedType.callSignatures) {
const signatureParts = createSignatureParts(signature);
typeElements.push(createSignatureDeclaration<CallSignatureDeclaration>(SyntaxKind.CallSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
}
for (const signature of resolvedType.constructSignatures) {
signature;
throw new Error("Construct signatures not implemented");
const signatureParts = createSignatureParts(signature);
typeElements.push(createSignatureDeclaration<ConstructSignatureDeclaration>(SyntaxKind.ConstructSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
}
if (resolvedType.stringIndexInfo) {
typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.stringIndexInfo, IndexKind.String));
}
if (resolvedType.numberIndexInfo) {
typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.stringIndexInfo, IndexKind.Number));
typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.numberIndexInfo, IndexKind.Number));
}
const members = resolvedType.members;
const properties = resolvedType.properties;
if (!properties) {
return typeElements;
}
members.forEach(memberSymbol => {
const oldDeclaration = memberSymbol.declarations && memberSymbol.declarations[0] as TypeElement;
for (const propertySymbol of properties) {
const propertyType = getTypeOfSymbol(propertySymbol);
const oldDeclaration = propertySymbol.declarations && propertySymbol.declarations[0] as TypeElement;
if (!oldDeclaration) {
return;
}
const kind = oldDeclaration.kind;
const memberName = getSynthesizedDeepClone(oldDeclaration.name);
const memberType = getTypeOfSymbol(memberSymbol);
switch (kind) {
case SyntaxKind.PropertySignature:
const optional = !!oldDeclaration.questionToken;
typeElements.push(createPropertySignature(
memberName
, optional ? createToken(SyntaxKind.QuestionToken) : undefined
, createTypeNode(memberType)
, /*initializer*/undefined));
break;
case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
const signatureType = getSignaturesOfSymbol(memberSymbol);
signatureType
createSignatureDeclaration
throw new Error("signature problems.");
// name ?: PropertyName;
// typeParameters ?: NodeArray<TypeParameterDeclaration>;
// parameters: NodeArray<ParameterDeclaration>;
// type ?: TypeNode;
case SyntaxKind.IndexSignature:
throw new Error("type literal constituent not implemented.");
default:
throw new Error("Unknown resolved member kind.");
const propertyName = getSynthesizedDeepClone(oldDeclaration.name);
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;;
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) {
const signatureParts = createSignatureParts(signature);
const methodDeclaration = createSignatureDeclaration<MethodSignature>(SyntaxKind.MethodSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type, propertyName, optionalToken);
methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration);
}
}
});
else {
typeElements.push(createPropertySignature(
propertyName
, optionalToken
, createTypeNode(propertyType)
, /*initializer*/undefined));
}
}
return typeElements.length ? typeElements : undefined;
}
}
+20 -11
View File
@@ -394,29 +394,37 @@ namespace ts {
: node;
}
export function createSignatureDeclaration<T extends SignatureDeclaration>(kind: SyntaxKind, name: string | PropertyName | undefined, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T {
// TODO: ask if we should have multiple implementations. Some T's can't have question token.
export function createSignatureDeclaration<T extends SignatureDeclaration>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): T;
export function createSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined): T;
export function createSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name?: string | PropertyName, questionToken?: QuestionToken): T {
const signatureDeclaration = createSynthesizedNode(kind) as T;
signatureDeclaration.name = asName(name);
signatureDeclaration.typeParameters = asNodeArray(typeParameters);
signatureDeclaration.parameters = asNodeArray(parameters);
signatureDeclaration.type = type;
signatureDeclaration.name = asName(name);
signatureDeclaration.questionToken = questionToken;
return signatureDeclaration;
}
export function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, name: string | PropertyName | undefined, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T {
return node.name !== name
|| node.typeParameters !== typeParameters
// TODO: figure out right type annotation for this function.
export function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T;
export function updateSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined): T;
export function updateSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name?: PropertyName, questionToken?: QuestionToken): T {
return node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
? <T>updateNode(createSignatureDeclaration(node.kind, name, typeParameters, parameters, type), node)
|| node.name !== name
|| node.questionToken !== questionToken
? updateNode(createSignatureDeclaration<T>(node.kind, typeParameters, parameters, type, name, questionToken), node)
: node;
}
// Signature elements
export function createPropertySignature(name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature {
export function createPropertySignature(name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature {
const propertySignature = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature;
propertySignature.name = name;
propertySignature.name = asName(name);
propertySignature.questionToken = questionToken;
propertySignature.type = type;
propertySignature.initializer = initializer;
@@ -511,12 +519,13 @@ namespace ts {
: node;
}
export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.asteriskToken = asteriskToken;
node.name = asName(name);
node.questionToken = questionToken;
node.typeParameters = asNodeArray(typeParameters);
node.parameters = asNodeArray(parameters);
node.type = type;
@@ -524,7 +533,7 @@ namespace ts {
return node;
}
export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
@@ -533,7 +542,7 @@ namespace ts {
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
: node;
}
+2
View File
@@ -2474,6 +2474,8 @@ namespace ts {
createTypeParameterDeclarationFromType(type: Type): TypeParameterDeclaration;
/** Note that the resulting type node cannot be checked. */
createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration
/** Note that the resulting type node cannot be checked. */
createParameterDeclarationFromSymbol(parameterSymbol: Symbol): ParameterDeclaration;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolAtLocation(node: Node): Symbol;
+25 -31
View File
@@ -245,6 +245,8 @@ namespace ts {
case SyntaxKind.EmptyStatement:
case SyntaxKind.OmittedExpression:
case SyntaxKind.DebuggerStatement:
case SyntaxKind.EndOfDeclarationMarker:
case SyntaxKind.MissingDeclaration:
// No need to visit nodes with no children.
return node;
@@ -260,18 +262,25 @@ namespace ts {
// Signatures and Signature Elements
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.MethodSignature:
return updateSignatureDeclaration(<SignatureDeclaration>node
, visitNode((<SignatureDeclaration>node).name, visitor, isPropertyName)
, nodesVisitor((<SignatureDeclaration>node).typeParameters, visitor, isTypeParameter)
, nodesVisitor((<SignatureDeclaration>node).parameters, visitor, isParameter)
, visitParameterList((<SignatureDeclaration>node).parameters, visitor, context, nodesVisitor)
, visitNode((<SignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.MethodSignature:
return updateSignatureDeclaration(<SignatureDeclaration & TypeElement>node
, nodesVisitor((<SignatureDeclaration & TypeElement>node).typeParameters, visitor, isTypeParameter)
, visitParameterList((<SignatureDeclaration & TypeElement>node).parameters, visitor, context, nodesVisitor)
, visitNode((<SignatureDeclaration & TypeElement>node).type, visitor, isTypeNode)
, visitNode((<SignatureDeclaration & TypeElement>node).name, visitor, isPropertyName)
, visitNode((<SignatureDeclaration & TypeElement>node).questionToken, visitor, isToken));
case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node
, nodesVisitor((<IndexSignatureDeclaration>node).parameters, visitor)
, visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor)
, visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode)
, nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator)
, nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
@@ -290,47 +299,32 @@ namespace ts {
return updateDecorator(<Decorator>node,
visitNode((<Decorator>node).expression, visitor, isExpression));
// Keyword Types and This
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ThisKeyword:
throw new Error("should be caught above");
// Types
case SyntaxKind.TypePredicate:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.TypeReference:
return updateTypeReferenceNode(<TypeReferenceNode>node
, visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName)
, nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
, visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName)
, nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
case SyntaxKind.FunctionType:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.ConstructorType:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.TypeQuery:
return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName));
case SyntaxKind.TypeLiteral:
return updateTypeLiteralNode((<TypeLiteralNode>node), nodesVisitor((<TypeLiteralNode>node).members, visitor));
case SyntaxKind.ArrayType:
return updateArrayTypeNode(<ArrayTypeNode>node, visitNode((<ArrayTypeNode>node).elementType, visitor, isTypeNode));
case SyntaxKind.TupleType:
return updateTypleTypeNode((<TupleTypeNode>node), nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return updateUnionOrIntersectionTypeNode(<UnionOrIntersectionTypeNode>node
, nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
, nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
case SyntaxKind.ParenthesizedType:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.ThisType:
@@ -366,7 +360,7 @@ namespace ts {
case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node
, nodesVisitor((<IndexSignatureDeclaration>node).parameters, visitor, isParameter)
, visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor)
, visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode)
, nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator)
, nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
@@ -383,8 +377,9 @@ namespace ts {
return updateMethod(<MethodDeclaration>node,
nodesVisitor((<MethodDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<MethodDeclaration>node).modifiers, visitor, isModifier),
(<MethodDeclaration>node).asteriskToken,
visitNode((<MethodDeclaration>node).asteriskToken, visitor, isToken),
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
visitNode((<MethodDeclaration>node).questionToken, visitor, isToken),
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
@@ -857,8 +852,7 @@ namespace ts {
visitNode((<PartiallyEmittedExpression>node).expression, visitor, isExpression));
default:
throw new Error("not handled");
// return node;
return node;
}
}
+31 -35
View File
@@ -85,56 +85,66 @@ namespace ts.codefix {
if (!(signatures && signatures.length > 0)) {
return undefined;
}
const optional = !!(symbol.flags & SymbolFlags.Optional);
if (declarations.length === 1) {
Debug.assert(signatures.length === 1);
// TODO: suppress any return type
// TODO: get parameters working.
// TODO: add support for type parameters.
const signature = signatures[0];
const newTypeParameters = signature.typeParameters && signature.typeParameters.map(checker.createTypeParameterDeclarationFromType);
const newParameterNodes = signature.getParameters().map(symbol => createParameterDeclarationFromSymbol(symbol, enclosingDeclaration, checker));
const returnType = createTypeNodeExceptAny(checker.getReturnTypeOfSignature(signature), checker);
return createStubbedMethod(modifiers, name, newTypeParameters, newParameterNodes, returnType);
const signatureParts = getSignatureParts(signature);
return createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
}
let signatureDeclarations = [];
for (let i = 0; i < signatures.length; i++) {
// TODO: make signatures instead of methods
const signature = signatures[i];
const newTypeParameters = signature.typeParameters && signature.typeParameters.map(checker.createTypeParameterDeclarationFromType);
const newParameterNodes = signature.getParameters().map(symbol => createParameterDeclarationFromSymbol(symbol, enclosingDeclaration, checker));
const returnType = createTypeNodeExceptAny(checker.getReturnTypeOfSignature(signature), checker);
const signatureParts = getSignatureParts(signature);
signatureDeclarations.push(createMethod(
/*decorators*/ undefined
, modifiers
, /*asteriskToken*/ undefined
, name
, newTypeParameters
, newParameterNodes
, returnType
, optional ? createToken(SyntaxKind.QuestionToken) : undefined
, signatureParts.typeParameters
, signatureParts.parameters
, signatureParts.type
, /*body*/undefined));
}
if (declarations.length > signatures.length) {
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 = createTypeNodeExceptAny(checker.getReturnTypeOfSignature(signature), checker);
signatureDeclarations.push(createStubbedMethod(modifiers, name, newTypeParameters, newParameterNodes, returnType));
const signatureParts = getSignatureParts(signature);
signatureDeclarations.push(createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
}
else {
Debug.assert(declarations.length === signatures.length);
const methodImplementingSignatures = createMethodImplementingSignatures(signatures, name, modifiers);
const methodImplementingSignatures = createMethodImplementingSignatures(signatures, name, optional, modifiers);
signatureDeclarations.push(methodImplementingSignatures);
}
return signatureDeclarations;
default:
return undefined;
}
type SignatureParts = {
typeParameters: TypeParameterDeclaration[];
parameters: ParameterDeclaration[];
type: TypeNode;
}
function getSignatureParts(signature: Signature): SignatureParts {
return {
typeParameters: signature.typeParameters && signature.typeParameters.map(checker.createTypeParameterDeclarationFromType),
parameters: signature.getParameters().map(symbol => checker.createParameterDeclarationFromSymbol(symbol)),
type: createTypeNodeExceptAny(checker.getReturnTypeOfSignature(signature), checker)
}
}
}
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, modifiers: Modifier[] | undefined): MethodDeclaration {
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
Debug.assert(signatures && signatures.length > 0);
let maxArgsIndex = 0;
@@ -153,7 +163,7 @@ namespace ts.codefix {
maxArgsSignature = sig;
}
}
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
const maxArgsParameterSymbolNames = signatures[maxArgsIndex].getParameters().map(symbol => symbol.getName());
const parameters: ParameterDeclaration[] = [];
@@ -186,17 +196,19 @@ namespace ts.codefix {
return createStubbedMethod(
modifiers
, name
, optional
, /*typeParameters*/undefined
, parameters
, /*returnType*/ undefined);
}
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
return createMethod(
/*decorators*/undefined
, modifiers
, /*asteriskToken*/undefined
, name
, optional ? createToken(SyntaxKind.QuestionToken) : undefined
, typeParameters
, parameters
, returnType
@@ -223,22 +235,6 @@ namespace ts.codefix {
return undefined;
}
function createParameterDeclarationFromSymbol(parameterSymbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker) {
const parameterDeclaration = parameterSymbol.getDeclarations()[0] as ParameterDeclaration;
const parameterType = checker.getTypeOfSymbolAtLocation(parameterSymbol, enclosingDeclaration);
const parameterTypeNode = checker.createTypeNode(parameterType);
// TODO: deep cloning of decorators/any node.
const parameterNode = createParameter(
parameterDeclaration.decorators && parameterDeclaration.decorators.map(getSynthesizedDeepClone)
, parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedDeepClone)
, parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken)
, getSynthesizedDeepClone(parameterDeclaration.name)
, parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken)
, parameterTypeNode
, /*initializer*/ undefined);
return parameterNode;
}
function createTypeNodeExceptAny(type: Type, checker: TypeChecker) {
const typeNode = checker.createTypeNode(type);
return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined;