Merge pull request #14709 from aozgaa/createTypeNode

Create type node
This commit is contained in:
Arthur Ozga 2017-03-27 12:58:32 -07:00 committed by GitHub
commit 5e4b8d66ff
69 changed files with 1601 additions and 286 deletions

View file

@ -61,6 +61,7 @@ namespace ts {
const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis;
const emitResolver = createResolver();
const nodeBuilder = createNodeBuilder();
const undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined");
undefinedSymbol.declarations = [];
@ -106,6 +107,9 @@ namespace ts {
getParameterType: getTypeAtPosition,
getReturnTypeOfSignature,
getNonNullableType,
typeToTypeNode: nodeBuilder.typeToTypeNode,
indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration,
signatureToSignatureDeclaration: nodeBuilder.signatureToSignatureDeclaration,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? getSymbolsInScope(location, meaning) : [];
@ -2198,6 +2202,584 @@ namespace ts {
return result;
}
function createNodeBuilder() {
let context: NodeBuilderContext;
return {
typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = typeToTypeNodeHelper(type);
const result = context.encounteredError ? undefined : resultingNode;
return result;
},
indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind);
const result = context.encounteredError ? undefined : resultingNode;
return result;
},
signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = signatureToSignatureDeclarationHelper(signature, kind);
const result = context.encounteredError ? undefined : resultingNode;
return result;
}
};
interface NodeBuilderContext {
readonly enclosingDeclaration: Node | undefined;
readonly flags: NodeBuilderFlags | undefined;
encounteredError: boolean;
inObjectTypeLiteral: boolean;
checkAlias: boolean;
symbolStack: Symbol[] | undefined;
}
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
return {
enclosingDeclaration,
flags,
encounteredError: false,
inObjectTypeLiteral: false,
checkAlias: true,
symbolStack: undefined
};
}
function typeToTypeNodeHelper(type: Type): TypeNode {
if (!type) {
context.encounteredError = true;
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
return undefined;
}
if (type.flags & TypeFlags.Any) {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
if (type.flags & TypeFlags.String) {
return createKeywordTypeNode(SyntaxKind.StringKeyword);
}
if (type.flags & TypeFlags.Number) {
return createKeywordTypeNode(SyntaxKind.NumberKeyword);
}
if (type.flags & TypeFlags.Boolean) {
return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
}
if (type.flags & TypeFlags.Enum) {
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (type.flags & (TypeFlags.StringLiteral)) {
return createLiteralTypeNode((createLiteral((<LiteralType>type).text)));
}
if (type.flags & (TypeFlags.NumberLiteral)) {
return createLiteralTypeNode((createNumericLiteral((<LiteralType>type).text)));
}
if (type.flags & TypeFlags.BooleanLiteral) {
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
}
if (type.flags & TypeFlags.EnumLiteral) {
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (type.flags & TypeFlags.Void) {
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
}
if (type.flags & TypeFlags.Undefined) {
return createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
}
if (type.flags & TypeFlags.Null) {
return createKeywordTypeNode(SyntaxKind.NullKeyword);
}
if (type.flags & TypeFlags.Never) {
return createKeywordTypeNode(SyntaxKind.NeverKeyword);
}
if (type.flags & TypeFlags.ESSymbol) {
return createKeywordTypeNode(SyntaxKind.SymbolKeyword);
}
if (type.flags & TypeFlags.NonPrimitive) {
return createKeywordTypeNode(SyntaxKind.ObjectKeyword);
}
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
if (context.inObjectTypeLiteral) {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowThisInObjectLiteral)) {
context.encounteredError = true;
}
}
return createThis();
}
const objectFlags = getObjectFlags(type);
if (objectFlags & ObjectFlags.Reference) {
Debug.assert(!!(type.flags & TypeFlags.Object));
return typeReferenceToTypeNode(<TypeReference>type);
}
if (objectFlags & ObjectFlags.ClassOrInterface) {
Debug.assert(!!(type.flags & TypeFlags.Object));
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
// TODO(aozgaa): handle type arguments.
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (type.flags & TypeFlags.TypeParameter) {
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (context.checkAlias && type.aliasSymbol) {
const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false);
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments);
return createTypeReferenceNode(name, typeArgumentNodes);
}
context.checkAlias = false;
if (type.flags & TypeFlags.Union) {
const formattedUnionTypes = formatUnionTypes((<UnionType>type).types);
const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes);
if (unionTypeNodes && unionTypeNodes.length > 0) {
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes);
}
else {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) {
context.encounteredError = true;
}
return undefined;
}
}
if (type.flags & TypeFlags.Intersection) {
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
}
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// The type is an object literal type.
return createAnonymousTypeNode(<ObjectType>type);
}
if (type.flags & TypeFlags.Index) {
const indexedType = (<IndexType>type).type;
const indexTypeNode = typeToTypeNodeHelper(indexedType);
return createTypeOperatorNode(indexTypeNode);
}
if (type.flags & TypeFlags.IndexedAccess) {
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType);
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType);
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
}
Debug.fail("Should be unreachable.");
function mapToTypeNodeArray(types: Type[]): TypeNode[] {
const result = [];
for (const type of types) {
const typeNode = typeToTypeNodeHelper(type);
if (typeNode) {
result.push(typeNode);
}
}
return result;
}
function createMappedTypeNodeFromType(type: MappedType) {
Debug.assert(!!(type.flags & TypeFlags.Object));
const typeParameter = getTypeParameterFromMappedType(type);
const typeParameterNode = typeParameterToDeclaration(typeParameter);
const templateType = getTemplateTypeFromMappedType(type);
const templateTypeNode = typeToTypeNodeHelper(templateType);
const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
}
function createAnonymousTypeNode(type: ObjectType): TypeNode {
const symbol = type.symbol;
if (symbol) {
// Always use 'typeof T' for type of class, enum, and module objects
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) ||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
shouldWriteTypeOfFunctionSymbol()) {
return createTypeQueryNodeFromSymbol(symbol);
}
else if (contains(context.symbolStack, symbol)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags
const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
}
else {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
}
else {
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type
if (!context.symbolStack) {
context.symbolStack = [];
}
context.symbolStack.push(symbol);
const result = createTypeNodeFromObjectType(type);
context.symbolStack.pop();
return result;
}
}
else {
// Anonymous types without a symbol are never circular.
return createTypeNodeFromObjectType(type);
}
function shouldWriteTypeOfFunctionSymbol() {
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static));
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
(symbol.parent || // is exported function symbol
forEach(symbol.declarations, declaration =>
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
// typeof is allowed only for static/non local functions
return contains(context.symbolStack, symbol); // it is type of the symbol uses itself recursively
}
}
}
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
if (type.objectFlags & ObjectFlags.Mapped) {
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
return createMappedTypeNodeFromType(<MappedType>type);
}
}
const resolved = resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
return createTypeLiteralNode(/*members*/ undefined);
}
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const signature = resolved.callSignatures[0];
return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType);
}
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
const signature = resolved.constructSignatures[0];
return <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType);
}
}
const saveInObjectTypeLiteral = context.inObjectTypeLiteral;
context.inObjectTypeLiteral = true;
const members = createTypeNodesFromResolvedType(resolved);
context.inObjectTypeLiteral = saveInObjectTypeLiteral;
return createTypeLiteralNode(members);
}
function createTypeQueryNodeFromSymbol(symbol: Symbol) {
const entityName = symbolToName(symbol, /*expectsIdentifier*/ false);
return createTypeQueryNode(entityName);
}
function typeReferenceToTypeNode(type: TypeReference) {
const typeArguments: Type[] = type.typeArguments || emptyArray;
if (type.target === globalArrayType) {
const elementType = typeToTypeNodeHelper(typeArguments[0]);
return createArrayTypeNode(elementType);
}
else if (type.target.objectFlags & ObjectFlags.Tuple) {
if (typeArguments.length > 0) {
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)));
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
return createTupleTypeNode(tupleConstituentNodes);
}
}
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyTuple)) {
context.encounteredError = true;
}
return undefined;
}
else {
const outerTypeParameters = type.target.outerTypeParameters;
let i = 0;
let qualifiedName: QualifiedName | undefined = undefined;
if (outerTypeParameters) {
const length = outerTypeParameters.length;
while (i < length) {
// Find group of type arguments for type parameters with the same declaring container.
const start = i;
const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i]);
do {
i++;
} while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
// When type parameters are their own type arguments for the whole group (i.e. we have
// the default outer type arguments), we don't show the group.
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true);
if (!qualifiedName) {
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
}
else {
Debug.assert(!qualifiedName.right);
qualifiedName.right = qualifiedNamePart;
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
}
}
}
}
let entityName: EntityName = undefined;
const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true);
if (qualifiedName) {
Debug.assert(!qualifiedName.right);
qualifiedName.right = nameIdentifier;
entityName = qualifiedName;
}
else {
entityName = nameIdentifier;
}
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined;
return createTypeReferenceNode(entityName, typeArgumentNodes);
}
}
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
const typeElements: TypeElement[] = [];
for (const signature of resolvedType.callSignatures) {
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature));
}
for (const signature of resolvedType.constructSignatures) {
typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature));
}
if (resolvedType.stringIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String));
}
if (resolvedType.numberIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number));
}
const properties = resolvedType.properties;
if (!properties) {
return typeElements;
}
for (const propertySymbol of properties) {
const propertyType = getTypeOfSymbol(propertySymbol);
const oldDeclaration = propertySymbol.declarations && propertySymbol.declarations[0] as TypeElement;
if (!oldDeclaration) {
return;
}
const propertyName = 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 methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature);
methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration);
}
}
else {
// TODO(aozgaa): should we create a node with explicit or implict any?
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
typeElements.push(createPropertySignature(
propertyName,
optionalToken,
propertyTypeNode,
/*initializer*/undefined));
}
}
return typeElements.length ? typeElements : undefined;
}
}
function indexInfoToIndexSignatureDeclarationHelper(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 = typeToTypeNodeHelper(indexInfo.type);
return createIndexSignatureDeclaration(
/*decorators*/ undefined,
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
[indexingParameter],
typeNode);
}
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
let returnTypeNode: TypeNode | TypePredicate;
if (signature.typePredicate) {
const typePredicate = signature.typePredicate;
const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((<IdentifierTypePredicate>typePredicate).parameterName) : createThisTypeNode();
const typeNode = typeToTypeNodeHelper(typePredicate.type);
returnTypeNode = createTypePredicateNode(parameterName, typeNode);
}
else {
const returnType = getReturnTypeOfSignature(signature);
returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
}
const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined;
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny);
}
function typeParameterToDeclaration(type: TypeParameter): TypeParameterDeclaration {
const constraint = getConstraintFromTypeParameter(type);
const constraintNode = constraint && typeToTypeNodeHelper(constraint);
const defaultParameter = getDefaultFromTypeParameter(type);
const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter);
const name = symbolToName(type.symbol, /*expectsIdentifier*/ true);
return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
}
function symbolToParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration {
const parameterDeclaration = <ParameterDeclaration>getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter);
const parameterType = getTypeOfSymbol(parameterSymbol);
const parameterTypeNode = typeToTypeNodeHelper(parameterType);
// TODO(aozgaa): In the future, check initializer accessibility.
const parameterNode = createParameter(
parameterDeclaration.decorators,
parameterDeclaration.modifiers,
parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken),
// Clone name to remove trivia.
getSynthesizedClone(parameterDeclaration.name),
parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken),
parameterTypeNode,
parameterDeclaration.initializer);
return parameterNode;
}
function symbolToName(symbol: Symbol, expectsIdentifier: true): Identifier;
function symbolToName(symbol: Symbol, expectsIdentifier: false): EntityName;
function symbolToName(symbol: Symbol, expectsIdentifier: boolean): EntityName {
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
let chain: Symbol[];
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
if (!isTypeParameter && context.enclosingDeclaration) {
chain = getSymbolChain(symbol, SymbolFlags.None, /*endOfChain*/ true);
Debug.assert(chain && chain.length > 0);
}
else {
chain = [symbol];
}
if (expectsIdentifier && chain.length !== 1
&& !context.encounteredError
&& !(context.flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier)) {
context.encounteredError = true;
}
return createEntityNameFromSymbolChain(chain, chain.length - 1);
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
Debug.assert(chain && 0 <= index && index < chain.length);
// const parentIndex = index - 1;
const symbol = chain[index];
let typeParameterString = "";
if (index > 0) {
const parentSymbol = chain[index - 1];
let typeParameters: TypeParameter[];
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
typeParameters = getTypeParametersOfClassOrInterface(parentSymbol);
}
else {
const targetSymbol = getTargetSymbol(parentSymbol);
if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) {
typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
}
}
if (typeParameters && typeParameters.length > 0) {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) {
context.encounteredError = true;
}
const writer = getSingleLineStringWriter();
const displayBuilder = getSymbolDisplayBuilder();
displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, context.enclosingDeclaration, 0);
typeParameterString = writer.string();
releaseStringWriter(writer);
}
}
const symbolName = getNameOfSymbol(symbol);
const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName;
const identifier = createIdentifier(symbolNameWithTypeParameters);
return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
}
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/false);
let parentSymbol: Symbol;
if (!accessibleSymbolChain ||
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
// Go up and add our parent.
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
if (parent) {
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
if (parentChain) {
parentSymbol = parent;
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
}
}
}
if (accessibleSymbolChain) {
return accessibleSymbolChain;
}
if (
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
endOfChain ||
// If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
!(!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) &&
// If a parent symbol is an anonymous type, don't write it.
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
return [symbol];
}
}
function getNameOfSymbol(symbol: Symbol): string {
const declaration = firstOrUndefined(symbol.declarations);
if (declaration) {
if (declaration.name) {
return declarationNameToString(declaration.name);
}
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
}
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) {
context.encounteredError = true;
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
}
return symbol.name;
}
}
}
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
const writer = getSingleLineStringWriter();
getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
@ -2466,6 +3048,7 @@ namespace ts {
}
}
function writeTypeList(types: Type[], delimiter: SyntaxKind) {
for (let i = 0; i < types.length; i++) {
if (i > 0) {

View file

@ -45,7 +45,7 @@ namespace ts {
* Creates a shallow, memberwise clone of a node with no source map location.
*/
/* @internal */
export function getSynthesizedClone<T extends Node>(node: T): T {
export function getSynthesizedClone<T extends Node>(node: T | undefined): T {
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
// the original node. We also need to exclude specific properties and only include own-
// properties (to skip members already defined on the shared prototype).
@ -166,23 +166,23 @@ namespace ts {
// Reserved words
export function createSuper() {
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.SuperKeyword);
return <SuperExpression>createSynthesizedNode(SyntaxKind.SuperKeyword);
}
export function createThis() {
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.ThisKeyword);
return <ThisExpression & Token<SyntaxKind.ThisKeyword>>createSynthesizedNode(SyntaxKind.ThisKeyword);
}
export function createNull() {
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.NullKeyword);
return <NullLiteral & Token<SyntaxKind.NullKeyword>>createSynthesizedNode(SyntaxKind.NullKeyword);
}
export function createTrue() {
return <BooleanLiteral>createSynthesizedNode(SyntaxKind.TrueKeyword);
return <BooleanLiteral & Token<SyntaxKind.TrueKeyword>>createSynthesizedNode(SyntaxKind.TrueKeyword);
}
export function createFalse() {
return <BooleanLiteral>createSynthesizedNode(SyntaxKind.FalseKeyword);
return <BooleanLiteral & Token<SyntaxKind.FalseKeyword>>createSynthesizedNode(SyntaxKind.FalseKeyword);
}
// Names
@ -213,6 +213,284 @@ namespace ts {
: node;
}
// Type Elements
export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
const signatureDeclaration = createSynthesizedNode(kind) as SignatureDeclaration;
signatureDeclaration.typeParameters = asNodeArray(typeParameters);
signatureDeclaration.parameters = asNodeArray(parameters);
signatureDeclaration.type = type;
return signatureDeclaration;
}
function updateSignatureDeclaration(node: SignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
? updateNode(createSignatureDeclaration(node.kind, typeParameters, parameters, type), node)
: node;
}
export function createFunctionTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.FunctionType, typeParameters, parameters, type) as FunctionTypeNode;
}
export function updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return <FunctionTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructorTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.ConstructorType, typeParameters, parameters, type) as ConstructorTypeNode;
}
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return <ConstructorTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createCallSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.CallSignature, typeParameters, parameters, type) as CallSignatureDeclaration;
}
export function updateCallSignatureDeclaration(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return <CallSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.ConstructSignature, typeParameters, parameters, type) as ConstructSignatureDeclaration;
}
export function updateConstructSignatureDeclaration(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return <ConstructSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createMethodSignature(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined) {
const methodSignature = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature;
methodSignature.name = asName(name);
methodSignature.questionToken = questionToken;
return methodSignature;
}
export function updateMethodSignature(node: MethodSignature, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined) {
return node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.name !== name
|| node.questionToken !== questionToken
? updateNode(createMethodSignature(typeParameters, parameters, type, name, questionToken), node)
: node;
}
// Types
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]) {
return <KeywordTypeNode>createSynthesizedNode(kind);
}
export function createThisTypeNode() {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createLiteralTypeNode(literal: Expression) {
const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
literalTypeNode.literal = literal;
return literalTypeNode;
}
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression) {
return node.literal !== literal
? updateNode(createLiteralTypeNode(literal), node)
: node;
}
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) {
const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
typeReference.typeName = asName(typeName);
typeReference.typeArguments = asNodeArray(typeArguments);
return typeReference;
}
export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray<TypeNode> | undefined) {
return node.typeName !== typeName
|| node.typeArguments !== typeArguments
? updateNode(createTypeReferenceNode(typeName, typeArguments), node)
: node;
}
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) {
const typePredicateNode = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode;
typePredicateNode.parameterName = asName(parameterName);
typePredicateNode.type = type;
return typePredicateNode;
}
export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) {
return node.parameterName !== parameterName
|| node.type !== type
? updateNode(createTypePredicateNode(parameterName, type), node)
: node;
}
export function createTypeQueryNode(exprName: EntityName) {
const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
typeQueryNode.exprName = exprName;
return typeQueryNode;
}
export function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName) {
return node.exprName !== exprName ? updateNode(createTypeQueryNode(exprName), node) : node;
}
export function createArrayTypeNode(elementType: TypeNode) {
const arrayTypeNode = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode;
arrayTypeNode.elementType = elementType;
return arrayTypeNode;
}
export function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode {
return node.elementType !== elementType
? updateNode(createArrayTypeNode(elementType), node)
: node;
}
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType, types: TypeNode[]): UnionTypeNode;
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.IntersectionType, types: TypeNode[]): IntersectionTypeNode;
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]): UnionOrIntersectionTypeNode;
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) {
const unionTypeNode = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
unionTypeNode.types = createNodeArray(types);
return unionTypeNode;
}
export function updateUnionOrIntersectionTypeNode(node: UnionOrIntersectionTypeNode, types: NodeArray<TypeNode>) {
return node.types !== types
? updateNode(createUnionOrIntersectionTypeNode(node.kind, types), node)
: node;
}
export function createTypeLiteralNode(members: TypeElement[]) {
const typeLiteralNode = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode;
typeLiteralNode.members = createNodeArray(members);
return typeLiteralNode;
}
export function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray<TypeElement>) {
return node.members !== members
? updateNode(createTypeLiteralNode(members), node)
: node;
}
export function createTupleTypeNode(elementTypes: TypeNode[]) {
const tupleTypeNode = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
tupleTypeNode.elementTypes = createNodeArray(elementTypes);
return tupleTypeNode;
}
export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: TypeNode[]) {
return node.elementTypes !== elementTypes
? updateNode(createTupleTypeNode(elementTypes), node)
: node;
}
export function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
const mappedTypeNode = createSynthesizedNode(SyntaxKind.MappedType) as MappedTypeNode;
mappedTypeNode.readonlyToken = readonlyToken;
mappedTypeNode.typeParameter = typeParameter;
mappedTypeNode.questionToken = questionToken;
mappedTypeNode.type = type;
return mappedTypeNode;
}
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
return node.readonlyToken !== readonlyToken
|| node.typeParameter !== typeParameter
|| node.questionToken !== questionToken
|| node.type !== type
? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node)
: node;
}
export function createTypeOperatorNode(type: TypeNode) {
const typeOperatorNode = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
typeOperatorNode.operator = SyntaxKind.KeyOfKeyword;
typeOperatorNode.type = type;
return typeOperatorNode;
}
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
return node.type !== type ? updateNode(createTypeOperatorNode(type), node) : node;
}
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
const indexedAccessTypeNode = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode;
indexedAccessTypeNode.objectType = objectType;
indexedAccessTypeNode.indexType = indexType;
return indexedAccessTypeNode;
}
export function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) {
return node.objectType !== objectType
|| node.indexType !== indexType
? updateNode(createIndexedAccessTypeNode(objectType, indexType), node)
: node;
}
// Type Declarations
export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
const typeParameter = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
typeParameter.name = asName(name);
typeParameter.constraint = constraint;
typeParameter.default = defaultType;
return typeParameter;
}
export function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
return node.name !== name
|| node.constraint !== constraint
|| node.default !== defaultType
? updateNode(createTypeParameterDeclaration(name, constraint, defaultType), node)
: node;
}
// Signature elements
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 = asName(name);
propertySignature.questionToken = questionToken;
propertySignature.type = type;
propertySignature.initializer = initializer;
return propertySignature;
}
export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
return node.name !== name
|| node.questionToken !== questionToken
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createPropertySignature(name, questionToken, type, initializer), node)
: node;
}
export function createIndexSignatureDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration {
const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration;
indexSignature.decorators = asNodeArray(decorators);
indexSignature.modifiers = asNodeArray(modifiers);
indexSignature.parameters = createNodeArray(parameters);
indexSignature.type = type;
return indexSignature;
}
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode) {
return node.parameters !== parameters
|| node.type !== type
|| node.decorators !== decorators
|| node.modifiers !== modifiers
? updateNode(createIndexSignatureDeclaration(decorators, modifiers, parameters, type), node)
: node;
}
// Signature elements
export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) {
@ -227,11 +505,12 @@ namespace ts {
return node;
}
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.dotDotDotToken !== dotDotDotToken
|| node.name !== name
|| node.questionToken !== questionToken
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer), node)
@ -273,12 +552,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 createMethodDeclaration(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 = createNodeArray(parameters);
node.type = type;
@ -286,7 +566,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
@ -295,7 +575,7 @@ namespace ts {
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
? updateNode(createMethodDeclaration(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
: node;
}
@ -1099,10 +1379,6 @@ namespace ts {
: node;
}
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode {
return <KeywordTypeNode>createSynthesizedNode(kind);
}
export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <FunctionDeclaration>createSynthesizedNode(SyntaxKind.FunctionDeclaration);
node.decorators = asNodeArray(decorators);
@ -1793,7 +2069,9 @@ namespace ts {
function asName(name: string | Identifier): Identifier;
function asName(name: string | BindingName): BindingName;
function asName(name: string | PropertyName): PropertyName;
function asName(name: string | Identifier | BindingName | PropertyName) {
function asName(name: string | EntityName): EntityName;
function asName(name: string | Identifier | ThisTypeNode): Identifier | ThisTypeNode;
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName | ThisTypeNode) {
return typeof name === "string" ? createIdentifier(name) : name;
}

View file

@ -125,6 +125,7 @@ namespace ts {
visitNodes(node.modifiers, visitor, isModifier),
node.asteriskToken,
node.name,
/*questionToken*/ undefined,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,

View file

@ -475,6 +475,7 @@ namespace ts {
/*modifiers*/ undefined,
node.dotDotDotToken,
getGeneratedNameForNode(node),
/*questionToken*/ undefined,
/*type*/ undefined,
visitNode(node.initializer, visitor, isExpression)
);
@ -540,6 +541,7 @@ namespace ts {
? undefined
: node.asteriskToken,
visitNode(node.name, visitor, isPropertyName),
visitNode(/*questionToken*/ undefined, visitor, isToken),
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,

View file

@ -2049,6 +2049,7 @@ namespace ts {
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
visitPropertyNameOfClassElement(node),
/*questionToken*/ undefined,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,

View file

@ -819,7 +819,7 @@ namespace ts {
body?: FunctionBody;
}
// For when we encounter a semicolon in a class declaration. ES6 allows these as class elements.
/** For when we encounter a semicolon in a class declaration. ES6 allows these as class elements.*/
export interface SemicolonClassElement extends ClassElement {
kind: SyntaxKind.SemicolonClassElement;
parent?: ClassDeclaration | ClassExpression;
@ -861,7 +861,11 @@ namespace ts {
| SyntaxKind.BooleanKeyword
| SyntaxKind.StringKeyword
| SyntaxKind.SymbolKeyword
| SyntaxKind.VoidKeyword;
| SyntaxKind.ThisKeyword
| SyntaxKind.VoidKeyword
| SyntaxKind.UndefinedKeyword
| SyntaxKind.NullKeyword
| SyntaxKind.NeverKeyword;
}
export interface ThisTypeNode extends TypeNode {
@ -1030,15 +1034,15 @@ namespace ts {
_primaryExpressionBrand: any;
}
export interface NullLiteral extends PrimaryExpression {
export interface NullLiteral extends PrimaryExpression, TypeNode {
kind: SyntaxKind.NullKeyword;
}
export interface BooleanLiteral extends PrimaryExpression {
export interface BooleanLiteral extends PrimaryExpression, TypeNode {
kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword;
}
export interface ThisExpression extends PrimaryExpression {
export interface ThisExpression extends PrimaryExpression, KeywordTypeNode {
kind: SyntaxKind.ThisKeyword;
}
@ -2472,6 +2476,14 @@ namespace ts {
/* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type;
getNonNullableType(type: Type): Type;
/** Note that the resulting nodes cannot be checked. */
typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
/** Note that the resulting nodes cannot be checked. */
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration;
/** Note that the resulting nodes cannot be checked. */
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolAtLocation(node: Node): Symbol;
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
@ -2523,6 +2535,16 @@ namespace ts {
/* @internal */ getTypeCount(): number;
}
export enum NodeBuilderFlags {
None = 0,
allowThisInObjectLiteral = 1 << 0,
allowQualifedNameInPlaceOfIdentifier = 1 << 1,
allowTypeParameterInQualifiedName = 1 << 2,
allowAnonymousIdentifier = 1 << 3,
allowEmptyUnionOrIntersection = 1 << 4,
allowEmptyTuple = 1 << 5
}
export interface SymbolDisplayBuilder {
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
@ -4073,7 +4095,7 @@ namespace ts {
export type Transformer<T extends Node> = (node: T) => T;
/**
* A function that accepts and possible transforms a node.
* A function that accepts and possibly transforms a node.
*/
export type Visitor = (node: Node) => VisitResult<Node>;

View file

@ -525,6 +525,10 @@ namespace ts {
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) {
case SyntaxKind.Identifier:
@ -740,8 +744,8 @@ namespace ts {
//
// let a: A.B.C;
//
// Calling isPartOfTypeNode would consider the qualified name A.B a type node. Only C or
// A.B.C is a type node.
// Calling isPartOfTypeNode would consider the qualified name A.B a type node.
// Only C and A.B.C are type nodes.
if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) {
return true;
}
@ -3713,10 +3717,14 @@ namespace ts {
return (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode)
|| kind === SyntaxKind.AnyKeyword
|| kind === SyntaxKind.NumberKeyword
|| kind === SyntaxKind.ObjectKeyword
|| kind === SyntaxKind.BooleanKeyword
|| kind === SyntaxKind.StringKeyword
|| kind === SyntaxKind.SymbolKeyword
|| kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.VoidKeyword
|| kind === SyntaxKind.UndefinedKeyword
|| kind === SyntaxKind.NullKeyword
|| kind === SyntaxKind.NeverKeyword
|| kind === SyntaxKind.ExpressionWithTypeArguments;
}

View file

@ -204,21 +204,17 @@ namespace ts {
* @param visitor The callback used to visit each child.
* @param context A lexical environment context for the visitor.
*/
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes): T | undefined;
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined;
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes): Node {
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor): Node {
if (node === undefined) {
return undefined;
}
const kind = node.kind;
// No need to visit nodes with no children.
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) {
return node;
}
// We do not yet support types.
if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.LiteralType)) {
// No need to visit nodes with no children.
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) || kind === SyntaxKind.ThisType) {
return node;
}
@ -227,6 +223,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;
@ -240,13 +238,53 @@ namespace ts {
return updateComputedPropertyName(<ComputedPropertyName>node,
visitNode((<ComputedPropertyName>node).expression, visitor, isExpression));
// Signature elements
// Signatures and Signature Elements
case SyntaxKind.FunctionType:
return updateFunctionTypeNode(<FunctionTypeNode>node,
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionTypeNode>node).parameters, visitor, context, nodesVisitor),
visitNode((<FunctionTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructorType:
return updateConstructorTypeNode(<ConstructorTypeNode>node,
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<ConstructorTypeNode>node).parameters, visitor, context, nodesVisitor),
visitNode((<ConstructorTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.CallSignature:
return updateCallSignatureDeclaration(<CallSignatureDeclaration>node,
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<CallSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<CallSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructSignature:
return updateConstructSignatureDeclaration(<ConstructSignatureDeclaration>node,
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<ConstructSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<ConstructSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.MethodSignature:
return updateMethodSignature(<MethodSignature>node,
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<MethodSignature>node).parameters, visitor, context, nodesVisitor),
visitNode((<MethodSignature>node).type, visitor, isTypeNode),
visitNode((<MethodSignature>node).name, visitor, isPropertyName),
visitNode((<MethodSignature>node).questionToken, tokenVisitor, isToken));
case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier),
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.Parameter:
return updateParameter(<ParameterDeclaration>node,
nodesVisitor((<ParameterDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<ParameterDeclaration>node).modifiers, visitor, isModifier),
(<ParameterDeclaration>node).dotDotDotToken,
visitNode((<ParameterDeclaration>node).dotDotDotToken, tokenVisitor, isToken),
visitNode((<ParameterDeclaration>node).name, visitor, isBindingName),
visitNode((<ParameterDeclaration>node).questionToken, tokenVisitor, isToken),
visitNode((<ParameterDeclaration>node).type, visitor, isTypeNode),
visitNode((<ParameterDeclaration>node).initializer, visitor, isExpression));
@ -254,7 +292,74 @@ namespace ts {
return updateDecorator(<Decorator>node,
visitNode((<Decorator>node).expression, visitor, isExpression));
// Type member
// Types
case SyntaxKind.TypeReference:
return updateTypeReferenceNode(<TypeReferenceNode>node,
visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName),
nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
case SyntaxKind.TypePredicate:
return updateTypePredicateNode(<TypePredicateNode>node,
visitNode((<TypePredicateNode>node).parameterName, visitor),
visitNode((<TypePredicateNode>node).type, visitor, isTypeNode));
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));
case SyntaxKind.ParenthesizedType:
Debug.fail("not implemented.");
case SyntaxKind.TypeOperator:
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
case SyntaxKind.IndexedAccessType:
return updateIndexedAccessTypeNode((<IndexedAccessTypeNode>node),
visitNode((<IndexedAccessTypeNode>node).objectType, visitor, isTypeNode),
visitNode((<IndexedAccessTypeNode>node).indexType, visitor, isTypeNode));
case SyntaxKind.MappedType:
return updateMappedTypeNode((<MappedTypeNode>node),
visitNode((<MappedTypeNode>node).readonlyToken, tokenVisitor, isToken),
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameter),
visitNode((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.LiteralType:
return updateLiteralTypeNode(<LiteralTypeNode>node,
visitNode((<LiteralTypeNode>node).literal, visitor, isExpression));
// Type Declarations
case SyntaxKind.TypeParameter:
return updateTypeParameterDeclaration(<TypeParameterDeclaration>node,
visitNode((<TypeParameterDeclaration>node).name, visitor, isIdentifier),
visitNode((<TypeParameterDeclaration>node).constraint, visitor, isTypeNode),
visitNode((<TypeParameterDeclaration>node).default, visitor, isTypeNode));
// Type members
case SyntaxKind.PropertySignature:
return updatePropertySignature((<PropertySignature>node),
visitNode((<PropertySignature>node).name, visitor, isPropertyName),
visitNode((<PropertySignature>node).questionToken, tokenVisitor, isToken),
visitNode((<PropertySignature>node).type, visitor, isTypeNode),
visitNode((<PropertySignature>node).initializer, visitor, isExpression));
case SyntaxKind.PropertyDeclaration:
return updateProperty(<PropertyDeclaration>node,
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),
@ -267,8 +372,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, tokenVisitor, isToken),
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
visitNode((<MethodDeclaration>node).questionToken, tokenVisitor, isToken),
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
@ -309,7 +415,7 @@ namespace ts {
case SyntaxKind.BindingElement:
return updateBindingElement(<BindingElement>node,
(<BindingElement>node).dotDotDotToken,
visitNode((<BindingElement>node).dotDotDotToken, tokenVisitor, isToken),
visitNode((<BindingElement>node).propertyName, visitor, isPropertyName),
visitNode((<BindingElement>node).name, visitor, isBindingName),
visitNode((<BindingElement>node).initializer, visitor, isExpression));
@ -362,7 +468,7 @@ namespace ts {
case SyntaxKind.FunctionExpression:
return updateFunctionExpression(<FunctionExpression>node,
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
(<FunctionExpression>node).asteriskToken,
visitNode((<FunctionExpression>node).asteriskToken, tokenVisitor, isToken),
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
@ -419,7 +525,7 @@ namespace ts {
case SyntaxKind.YieldExpression:
return updateYield(<YieldExpression>node,
(<YieldExpression>node).asteriskToken,
visitNode((<YieldExpression>node).asteriskToken, tokenVisitor, isToken),
visitNode((<YieldExpression>node).expression, visitor, isExpression));
case SyntaxKind.SpreadElement:
@ -555,7 +661,7 @@ namespace ts {
return updateFunctionDeclaration(<FunctionDeclaration>node,
nodesVisitor((<FunctionDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<FunctionDeclaration>node).modifiers, visitor, isModifier),
(<FunctionDeclaration>node).asteriskToken,
visitNode((<FunctionDeclaration>node).asteriskToken, tokenVisitor, isToken),
visitNode((<FunctionDeclaration>node).name, visitor, isIdentifier),
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context, nodesVisitor),

View file

@ -31,37 +31,55 @@ namespace ts.codefix {
return undefined;
}
let typeString = "any";
let typeNode: TypeNode;
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeString = checker.typeToString(widenedType);
typeNode = checker.typeToTypeNode(widenedType, classDeclaration) || typeNode;
}
const startPos = classDeclaration.members.pos;
typeNode = typeNode ? typeNode : createKeywordTypeNode(SyntaxKind.AnyKeyword);
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
const property = createProperty(
/*decorators*/undefined,
/*modifiers*/ undefined,
token.getText(sourceFile),
/*questionToken*/ undefined,
typeNode,
/*initializer*/ undefined);
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
"x",
/*questionToken*/ undefined,
stringTypeNode,
/*initializer*/ undefined);
const indexSignature = createIndexSignatureDeclaration(
/*decorators*/undefined,
/*modifiers*/ undefined,
[indexingParameter],
typeNode);
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: `${token.getFullText(sourceFile)}: ${typeString};`
}]
}]
changes: propertyChangeTracker.getChanges()
},
{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: `[name: string]: ${typeString};`
}]
}]
changes: indexSignatureChangeTracker.getChanges()
}];
}
}

View file

@ -19,10 +19,9 @@ namespace ts.codefix {
const checker = context.program.getTypeChecker();
if (isClassLike(token.parent)) {
const classDecl = token.parent as ClassLikeDeclaration;
const startPos = classDecl.members.pos;
const classDeclaration = token.parent as ClassLikeDeclaration;
const extendsNode = getClassExtendsHeritageClauseElement(classDecl);
const extendsNode = getClassExtendsHeritageClauseElement(classDeclaration);
const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode);
// Note that this is ultimately derived from a map indexed by symbol names,
@ -30,18 +29,12 @@ namespace ts.codefix {
const extendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType);
const abstractAndNonPrivateExtendsSymbols = extendsSymbols.filter(symbolPointsToNonPrivateAndAbstractMember);
const insertion = getMissingMembersInsertion(classDecl, abstractAndNonPrivateExtendsSymbols, checker, context.newLineCharacter);
if (insertion.length) {
const newNodes = createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, checker);
const changes = newNodesToChanges(newNodes, getOpenBraceOfClassLike(classDeclaration, sourceFile), context);
if (changes && changes.length > 0) {
return [{
description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: insertion
}]
}]
changes
}];
}
}

View file

@ -11,14 +11,14 @@ namespace ts.codefix {
const token = getTokenAtPosition(sourceFile, start);
const checker = context.program.getTypeChecker();
const classDecl = getContainingClass(token);
if (!classDecl) {
const classDeclaration = getContainingClass(token);
if (!classDeclaration) {
return undefined;
}
const startPos: number = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
const classType = checker.getTypeAtLocation(classDeclaration) as InterfaceType;
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDeclaration);
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
@ -31,43 +31,36 @@ namespace ts.codefix {
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
let insertion = getMissingIndexSignatureInsertion(implementedType, IndexKind.Number, classDecl, hasNumericIndexSignature);
insertion += getMissingIndexSignatureInsertion(implementedType, IndexKind.String, classDecl, hasStringIndexSignature);
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
let newNodes: Node[] = [];
createAndAddMissingIndexSignatureDeclaration(implementedType, IndexKind.Number, hasNumericIndexSignature, newNodes);
createAndAddMissingIndexSignatureDeclaration(implementedType, IndexKind.String, hasStringIndexSignature, newNodes);
newNodes = newNodes.concat(createMissingMemberNodes(classDeclaration, nonPrivateMembers, checker));
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
if (insertion) {
pushAction(result, insertion, message);
if (newNodes.length > 0) {
pushAction(result, newNodes, message);
}
}
return result;
function getMissingIndexSignatureInsertion(type: InterfaceType, kind: IndexKind, enclosingDeclaration: ClassLikeDeclaration, hasIndexSigOfKind: boolean) {
if (!hasIndexSigOfKind) {
const IndexInfoOfKind = checker.getIndexInfoOfType(type, kind);
if (IndexInfoOfKind) {
const writer = getSingleLineStringWriter();
checker.getSymbolDisplayBuilder().buildIndexSignatureDisplay(IndexInfoOfKind, writer, kind, enclosingDeclaration);
const result = writer.string();
releaseStringWriter(writer);
return result;
}
function createAndAddMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind, hasIndexSigOfKind: boolean, newNodes: Node[]): void {
if (hasIndexSigOfKind) {
return;
}
return "";
const indexInfoOfKind = checker.getIndexInfoOfType(type, kind);
if (!indexInfoOfKind) {
return;
}
const newIndexSignatureDeclaration = checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration);
newNodes.push(newIndexSignatureDeclaration);
}
function pushAction(result: CodeAction[], insertion: string, description: string): void {
function pushAction(result: CodeAction[], newNodes: Node[], description: string): void {
const newAction: CodeAction = {
description: description,
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: insertion
}]
}]
changes: newNodesToChanges(newNodes, openBrace, context)
};
result.push(newAction);
}

View file

@ -16,7 +16,7 @@ namespace ts.codefix {
return undefined;
}
// figure out if the this access is actuall inside the supercall
// figure out if the `this` access is actually inside the supercall
// i.e. super(this.a), since in that case we won't suggest a fix
if (superCall.expression && superCall.expression.kind == SyntaxKind.CallExpression) {
const arguments = (<CallExpression>superCall.expression).arguments;

View file

@ -1,47 +1,88 @@
/* @internal */
namespace ts.codefix {
export function newNodesToChanges(newNodes: Node[], insertAfter: Node, context: CodeFixContext) {
const sourceFile = context.sourceFile;
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
for (const newNode of newNodes) {
changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode, { suffix: context.newLineCharacter });
}
const changes = changeTracker.getChanges();
if (!some(changes)) {
return changes;
}
Debug.assert(changes.length === 1);
const consolidatedChanges: FileTextChanges[] = [{
fileName: changes[0].fileName,
textChanges: [{
span: changes[0].textChanges[0].span,
newText: changes[0].textChanges.reduce((prev, cur) => prev + cur.newText, "")
}]
}];
return consolidatedChanges;
}
/**
* Finds members of the resolved type that are missing in the class pointed to by class decl
* and generates source code for the missing members.
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
* @returns Empty string iff there are no member insertions.
*/
export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string {
export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker): Node[] {
const classMembers = classDeclaration.symbol.members;
const missingMembers = possiblyMissingSymbols.filter(symbol => !classMembers.has(symbol.getName()));
let insertion = "";
let newNodes: Node[] = [];
for (const symbol of missingMembers) {
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
const newNode = createNewNodeForMemberSymbol(symbol, classDeclaration, checker);
if (newNode) {
if (Array.isArray(newNode)) {
newNodes = newNodes.concat(newNode);
}
else {
newNodes.push(newNode);
}
}
}
return insertion;
return newNodes;
}
/**
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
*/
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
function createNewNodeForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Node[] | Node | undefined {
const declarations = symbol.getDeclarations();
if (!(declarations && declarations.length)) {
return "";
return undefined;
}
const declaration = declarations[0] as Declaration;
const name = declaration.name ? declaration.name.getText() : undefined;
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
// Clone name to remove leading trivia.
const name = getSynthesizedClone(<PropertyName>declaration.name);
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined;
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
const optional = !!(symbol.flags & SymbolFlags.Optional);
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None);
return `${visibility}${name}: ${typeString};${newlineChar}`;
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration);
const property = createProperty(
/*decorators*/undefined,
modifiers,
name,
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
typeNode,
/*initializer*/ undefined);
return property;
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
// The signature for the implementation appears as an entry in `signatures` iff
@ -52,109 +93,142 @@ namespace ts.codefix {
// (eg: an abstract method or interface declaration), there is a 1-1
// correspondence of declarations and signatures.
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
if (!(signatures && signatures.length > 0)) {
return "";
if (!some(signatures)) {
return undefined;
}
if (declarations.length === 1) {
Debug.assert(signatures.length === 1);
const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
return getStubbedMethod(visibility, name, sigString, newlineChar);
const signature = signatures[0];
return signatureToMethodDeclaration(signature, enclosingDeclaration, createStubbedMethodBody());
}
let result = "";
const signatureDeclarations: MethodDeclaration[] = [];
for (let i = 0; i < signatures.length; i++) {
const sigString = checker.signatureToString(signatures[i], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
result += `${visibility}${name}${sigString};${newlineChar}`;
const signature = signatures[i];
const methodDeclaration = signatureToMethodDeclaration(signature, enclosingDeclaration);
if (methodDeclaration) {
signatureDeclarations.push(methodDeclaration);
}
}
// If there is a declaration with a body, it is the last declaration,
// and it isn't caught by `getSignaturesOfType`.
let bodySig: Signature | undefined = undefined;
if (declarations.length > signatures.length) {
bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
const methodDeclaration = signatureToMethodDeclaration(signature, enclosingDeclaration, createStubbedMethodBody());
if (methodDeclaration) {
signatureDeclarations.push(methodDeclaration);
}
}
else {
Debug.assert(declarations.length === signatures.length);
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
const methodImplementingSignatures = createMethodImplementingSignatures(signatures, name, optional, modifiers);
signatureDeclarations.push(methodImplementingSignatures);
}
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
result += getStubbedMethod(visibility, name, sigString, newlineChar);
return result;
return signatureDeclarations;
default:
return "";
return undefined;
}
function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) {
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration);
if (signatureDeclaration) {
signatureDeclaration.decorators = undefined;
signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
signatureDeclaration.body = body;
}
return signatureDeclaration;
}
}
function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration;
newSignatureDeclaration.parent = enclosingDeclaration;
newSignatureDeclaration.name = signatures[0].getDeclaration().name;
let maxNonRestArgs = -1;
let maxArgsIndex = 0;
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
/** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments,
* this is one of them.
*/
let maxArgsSignature = signatures[0];
let minArgumentCount = signatures[0].minArgumentCount;
let hasRestParameter = false;
let someSigHasRestParameter = false;
for (let i = 0; i < signatures.length; i++) {
const sig = signatures[i];
minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount);
hasRestParameter = hasRestParameter || sig.hasRestParameter;
const nonRestLength = sig.parameters.length - (sig.hasRestParameter ? 1 : 0);
if (nonRestLength > maxNonRestArgs) {
maxNonRestArgs = nonRestLength;
maxArgsIndex = i;
if (sig.hasRestParameter) {
someSigHasRestParameter = true;
}
if (sig.parameters.length >= maxArgsSignature.parameters.length && (!sig.hasRestParameter || maxArgsSignature.hasRestParameter)) {
maxArgsSignature = sig;
}
}
const maxArgsParameterSymbolNames = signatures[maxArgsIndex].getParameters().map(symbol => symbol.getName());
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.getName());
const optionalToken = createToken(SyntaxKind.QuestionToken);
newSignatureDeclaration.parameters = createNodeArray<ParameterDeclaration>();
const parameters: ParameterDeclaration[] = [];
for (let i = 0; i < maxNonRestArgs; i++) {
const newParameter = createParameterDeclarationWithoutType(i, minArgumentCount, newSignatureDeclaration);
newSignatureDeclaration.parameters.push(newParameter);
const anyType = createKeywordTypeNode(SyntaxKind.AnyKeyword);
const newParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
maxArgsParameterSymbolNames[i],
/*questionToken*/ i >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
anyType,
/*initializer*/ undefined);
parameters.push(newParameter);
}
if (hasRestParameter) {
const restParameter = createParameterDeclarationWithoutType(maxNonRestArgs, minArgumentCount, newSignatureDeclaration);
restParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
newSignatureDeclaration.parameters.push(restParameter);
if (someSigHasRestParameter) {
const anyArrayType = createArrayTypeNode(createKeywordTypeNode(SyntaxKind.AnyKeyword));
const restParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createToken(SyntaxKind.DotDotDotToken),
maxArgsParameterSymbolNames[maxNonRestArgs] || "rest",
/*questionToken*/ maxNonRestArgs >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
anyArrayType,
/*initializer*/ undefined);
parameters.push(restParameter);
}
return checker.getSignatureFromDeclaration(newSignatureDeclaration);
function createParameterDeclarationWithoutType(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration {
const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
newParameter.symbol = new SymbolConstructor(SymbolFlags.FunctionScopedVariable, maxArgsParameterSymbolNames[index] || "rest");
newParameter.symbol.valueDeclaration = newParameter;
newParameter.symbol.declarations = [newParameter];
newParameter.parent = enclosingSignatureDeclaration;
if (index >= minArgCount) {
newParameter.questionToken = optionalToken;
}
return newParameter;
}
return createStubbedMethod(
modifiers,
name,
optional,
/*typeParameters*/undefined,
parameters,
/*returnType*/ undefined);
}
export function getStubbedMethod(visibility: string, name: string, sigString = "()", newlineChar: string): string {
return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
return createMethodDeclaration(
/*decorators*/ undefined,
modifiers,
/*asteriskToken*/ undefined,
name,
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
typeParameters,
parameters,
returnType,
createStubbedMethodBody());
}
function getMethodBodyStub(newlineChar: string) {
return ` {${newlineChar}throw new Error('Method not implemented.');${newlineChar}}${newlineChar}`;
function createStubbedMethodBody() {
return createBlock(
[createThrow(
createNew(
createIdentifier("Error"),
/*typeArguments*/undefined,
[createLiteral("Method not implemented.")]))],
/*multiline*/true);
}
function getVisibilityPrefixWithSpace(flags: ModifierFlags): string {
function createVisibilityModifier(flags: ModifierFlags) {
if (flags & ModifierFlags.Public) {
return "public ";
return createToken(SyntaxKind.PublicKeyword);
}
else if (flags & ModifierFlags.Protected) {
return "protected ";
return createToken(SyntaxKind.ProtectedKeyword);
}
return "";
return undefined;
}
const SymbolConstructor = objectAllocator.getSymbolConstructor();
}

View file

@ -274,9 +274,9 @@ namespace ts.textChanges {
}
/**
* This function should be used to insert nodes in lists when nodes don't carry separators as the part of the node range,
* i.e. arguments in arguments lists, parameters in parameter lists etc. Statements or class elements are different in sense that
* for them separators are treated as the part of the node.
* This function should be used to insert nodes in lists when nodes don't carry separators as the part of the node range,
* i.e. arguments in arguments lists, parameters in parameter lists etc.
* Note that separators are part of the node in statements and class elements.
*/
public insertNodeInListAfter(sourceFile: SourceFile, after: Node, newNode: Node) {
const containingList = formatting.SmartIndenter.getContainingList(after, sourceFile);
@ -484,7 +484,7 @@ namespace ts.textChanges {
private static normalize(changes: Change[]) {
// order changes by start position
const normalized = stableSort(changes, (a, b) => a.range.pos - b.range.pos);
// verify that end position of the change is less than start position of the next change
// verify that change intervals do not overlap, except possibly at end points.
for (let i = 0; i < normalized.length - 2; i++) {
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos);
}
@ -549,7 +549,7 @@ namespace ts.textChanges {
};
function assignPositionsToNode(node: Node): Node {
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray);
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
// create proxy node for non synthesized nodes
const newNode = nodeIsSynthesized(visited)
? visited

View file

@ -1384,4 +1384,8 @@ namespace ts {
// First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile);
}
export function getOpenBraceOfClassLike(declaration: ClassLikeDeclaration, sourceFile: SourceFile) {
return getTokenAtPosition(sourceFile, declaration.members.pos - 1);
}
}

View file

@ -8,6 +8,6 @@
verify.rangeAfterCodeFix(`
f(): void{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -28,4 +28,4 @@ verify.rangeAfterCodeFix(`
e: this;
f: A;
g: string;
`);
`);

View file

@ -5,6 +5,7 @@
//// abstract f(a: number, b: string): this;
//// abstract f(a: string, b: number): Function;
//// abstract f(a: string): Function;
//// abstract foo(): number;
//// }
////
//// class C extends A {[| |]}
@ -15,6 +16,9 @@ verify.rangeAfterCodeFix(`
f(a: string, b: number): Function;
f(a: string): Function;
f(a: any, b?: any) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
foo(): number {
throw new Error("Method not implemented.");
}
`);

View file

@ -8,6 +8,6 @@
verify.rangeAfterCodeFix(`
f(): this {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -4,10 +4,9 @@
//// abstract f(x: T): T;
//// }
////
//// class C extends A<number> {[|
//// |]}
//// class C extends A<number> {[| |]}
verify.rangeAfterCodeFix(`f(x: number): number{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -4,10 +4,9 @@
//// abstract f(x: T): T;
//// }
////
//// class C<U> extends A<U> {[|
//// |]}
//// class C<U> extends A<U> {[| |]}
verify.rangeAfterCodeFix(`f(x: U): U{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -4,8 +4,7 @@
//// private abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
//// class C extends A {[| |]}
// We don't know how to fix this problem. We can:
// 1) Make x protected, and then insert.

View file

@ -4,17 +4,12 @@
//// abstract x: number;
//// abstract y: this;
//// abstract z: A;
//// abstract foo(): number;
//// }
////
//// class C extends A {[|
//// |]}
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
x: number;
y: this;
z: A;
foo(): number {
throw new Error('Method not implemented.');
}
`);

View file

@ -4,8 +4,7 @@
//// protected abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
protected x: number;

View file

@ -4,8 +4,8 @@
//// public abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
public x: number;

View file

@ -6,8 +6,8 @@
//// abstract z: number;
//// }
////
//// class C extends A {[| |]
//// constructor(public x: number) { super(); }
//// class C extends A {[|
//// |]constructor(public x: number) { super(); }
//// y: number;
//// }

View file

@ -8,6 +8,6 @@
verify.rangeAfterCodeFix(`
f(): void{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// class A {
//// foo() {
//// return class { x: number; }
//// }
//// bar() {
//// return new class { x: number; }
//// }
//// }
//// class C implements A {[| |]}
verify.not.codeFixAvailable();

View file

@ -8,11 +8,11 @@
////
//// }
////
//// class C3 implements C2 {[|
//// class C3 implements C2 {[|
//// |]f2(){}
//// }
verify.rangeAfterCodeFix(`f1(): void{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -9,6 +9,6 @@
verify.rangeAfterCodeFix(`
method(a: number, b: string): boolean;
method(a: string | number, b?: string | number): boolean | Function {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
method(a: string, b: number): Function;
method(a: string): Function;
method(a: string | number, b?: string | number): boolean | Function {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
//// class A {
//// A: typeof A;
//// }
//// class D implements A {[| |]}
verify.rangeAfterCodeFix(`
A: typeof A;
`);

View file

@ -24,8 +24,7 @@
//// }
////
//// interface I6 extends C4 {}
//// class C5 implements I6 {[|
//// |]}
//// class C5 implements I6 {[| |]}
/**

View file

@ -1,20 +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,15 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// x: number[];
//// y: Array<number>;
//// z: [number, string, I];
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
x: number[];
y: number[];
z: [number, string, I];
`);

View file

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// (x: number, b: string): number;
//// }
//// class C implements I {[| |]}
verify.not.codeFixAvailable();

View file

@ -0,0 +1,27 @@
/// <reference path='fourslash.ts' />
// @lib: es2017
//// namespace N {
//// /**enum prefix */
//// export enum /**enum identifier prefix */ E /**open-brace prefix*/ {
//// /* literal prefix */ a /** comma prefix */,
//// /* literal prefix */ b /** comma prefix */,
//// /* literal prefix */ c
//// /** close brace prefix */ }
//// /** interface prefix */
//// export interface /**interface name prefix */ I /**open-brace prefix*/ {
//// /** property prefix */ a /** colon prefix */: /** enum literal prefix 1*/ E /** dot prefix */. /** enum literal prefix 2*/a;
//// /** property prefix */ b /** colon prefix */: /** enum prefix */ E;
//// /**method signature prefix */foo /**open angle prefix */< /**type parameter name prefix */ X /** closing angle prefix */> /**open paren prefix */(/** parameter prefix */ a/** colon prefix */: /** parameter type prefix */ X /** close paren prefix */) /** colon prefix */: /** return type prefix */ string /** semicolon prefix */;
//// /**close-brace prefix*/ }
//// /**close-brace prefix*/ }
//// class C implements N.I {[| |]}
verify.rangeAfterCodeFix(`
a: N.E.a;
b: N.E;
foo<X>(a: X): string {
throw new Error("Method not implemented.");
}
`);

View file

@ -7,15 +7,15 @@
//// [2]: boolean;
//// }
////
//// class C implements I {[| |]}
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
["foo"](o: any): boolean {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
["x"]: boolean;
[1](): string {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[2]: boolean;
`);

View file

@ -17,35 +17,34 @@
//// [Symbol.toStringTag]: string;
//// [Symbol.unscopables]: any;
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
[Symbol.hasInstance](o: any): boolean {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.isConcatSpreadable]: boolean;
[Symbol.iterator]() {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.match]: boolean;
[Symbol.replace](...args: {}) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.search](str: string): number {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.species](): number {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.split](str: string, limit?: number): {} {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.toPrimitive](hint: "number"): number;
[Symbol.toPrimitive](hint: "default"): number;
[Symbol.toPrimitive](hint: "string"): string;
[Symbol.toPrimitive](hint: any) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
[Symbol.toStringTag]: string;
[Symbol.unscopables]: any;

View file

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// new (x: number, b: string);
//// }
//// class C implements I {[| |]}
verify.not.codeFixAvailable();

View file

@ -7,7 +7,6 @@
//// x: number;
//// }
////
//// class C implements I1,I2 {[|
//// |]}
//// class C implements I1,I2 {[| |]}
verify.codeFixAvailable();

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// x: {};
//// }
////
//// class C implements I {[|
//// |]constructor() { }
//// }
verify.rangeAfterCodeFix(`
x: {};
`);

View file

@ -9,10 +9,9 @@
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
//// class C1 implements N1.I1 {[| |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

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

View file

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
//// interface I<X> {
//// x: keyof X;
//// }
//// class C<Y> implements I<Y> {[| |]}
verify.rangeAfterCodeFix(`
x: keyof Y;
`);

View file

@ -0,0 +1,13 @@
/// <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,10 @@
/// <reference path='fourslash.ts' />
//// interface I<X> {
//// x: { readonly [K in keyof X]: X[K] };
//// }
//// class C<Y> implements I<Y> {[| |]}
verify.rangeAfterCodeFix(`
x: { readonly [K in keyof X]: Y[K]; };
`);

View file

@ -0,0 +1,58 @@
/// <reference path='fourslash.ts' />
// @lib: es2017
//// /** asdf */
//// interface I {
//// 1;
//// 2;
//// 3;
//// 4;
//// 5;
//// 6;
//// 7;
//// 8;
//// 9;
//// 10;
//// 11;
//// 12;
//// 13;
//// 14;
//// 15;
//// 16;
//// 17;
//// 18;
//// 19;
//// 20;
//// 21;
//// 22;
//// /** a nice safe prime */
//// 23;
//// }
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
1: any;
2: any;
3: any;
4: any;
5: any;
6: any;
7: any;
8: any;
9: any;
10: any;
11: any;
12: any;
13: any;
14: any;
15: any;
16: any;
17: any;
18: any;
19: any;
20: any;
21: any;
22: any;
23: any;
`);

View file

@ -4,11 +4,10 @@
//// f(x: number, y: this): I
//// }
////
//// class C implements I {[|
//// |]}
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
f(x: number,y: this): I {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// f(i: any): i is I;
//// f(): this is I;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
f(i: any): i is I;
f(): this is I;
f(i?: any) {
throw new Error("Method not implemented.");
}
`);

View file

@ -8,12 +8,11 @@
//// }
////
//// class C implements I1,I2 {[|
//// y: number;
//// |]}
//// |]y: number;
//// }
verify.rangeAfterCodeFix(`
x: number;
y: number;
`);
verify.not.codeFixAvailable();

View file

@ -8,12 +8,11 @@
//// }
////
//// class C implements I1,I2 {[|
//// x: number;
//// |]}
//// |]x: number;
//// }
verify.rangeAfterCodeFix(`
y: number;
x: number;
`);
verify.not.codeFixAvailable();

View file

@ -7,7 +7,6 @@
//// x: string;
//// }
////
//// class C implements I1,I2 {[|
//// |]}
//// class C implements I1,I2 {[| |]}
verify.codeFixAvailable();

View file

@ -9,20 +9,19 @@
//// h();
//// }
////
//// class C1 implements I1 {[|
//// |]}
//// class C1 implements I1 {[| |]}
verify.rangeAfterCodeFix(`
x: number;
y: number;
z: number;
f() {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
g() {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
h() {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
method(a: string, b: number): Function;
method(a: string): Function;
method(a: any, b?: any) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
method(a: string, ...b: number[]): Function;
method(a: string): Function;
method(a: any, ...b?: any[]) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
method(a: string, b: number): Function;
method(a: string): Function;
method(a: any, b?: any, ...rest?: any[]) {
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -8,9 +8,7 @@
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
//// class C1 implements N1.I1 {[| |]}
verify.rangeAfterCodeFix(`
x: number;

View file

@ -0,0 +1,19 @@
/// <reference path='fourslash.ts' />
// @lib: es2017
//// enum E { a,b,c }
//// interface I {
//// x: E;
//// y: E.a
//// z: symbol;
//// w: object;
//// }
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
x: E;
y: E.a;
z: symbol;
w: object;
`);

View file

@ -4,7 +4,7 @@
//// constructor(public x: number) { }
//// }
////
//// class B implements A {[| |]}
//// class B implements A {[| |]}
verify.not.codeFixAvailable();

View file

@ -0,0 +1,34 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// a0: {};
//// a1: { (b1: number, c1: string): number; };
//// a2: (b2: number, c2: string) => number;
//// a3: { (b3: number, c3: string): number, x: number };
////
//// a4: { new (b1: number, c1: string): number; };
//// a5: new (b2: number, c2: string) => number;
//// a6: { new (b3: number, c3: string): number, x: number };
////
//// a7: { foo(b7: number, c7: string): number };
////
//// a8: { (b81: number, c81: string): number, new (b82: number, c82: string): number; };
////
//// a9: { (b9: number, c9: string): number; [d9: number]: I };
//// a10: { (b10: number, c10: string): number; [d10: string]: I };
//// }
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
a0: {};
a1: (b1: number, c1: string) => number;
a2: (b2: number, c2: string) => number;
a3: { (b3: number, c3: string): number; x: number; };
a4: new (b1: number, c1: string) => number;
a5: new (b2: number, c2: string) => number;
a6: { new (b3: number, c3: string): number; x: number; };
a7: { foo(b7: number, c7: string): number; };
a8: { (b81: number, c81: string): number; new (b82: number, c82: string): number; };
a9: { (b9: number, c9: string): number; [d9: number]: I; };
a10: { (b10: number, c10: string): number; [d10: string]: I; };
`);

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// namespace N {
//// export interface I {
//// y: I;
//// }
//// }
//// class C1 implements N.I {[| |]}
verify.rangeAfterCodeFix(`
y: N.I;
`);

View file

@ -6,8 +6,8 @@
//// z: number & { __iBrand: any };
//// }
////
//// class C implements I {[| |]
//// constructor(public x: number) { }
//// class C implements I {[|
//// |]constructor(public x: number) { }
//// y: number;
//// }

View file

@ -4,7 +4,7 @@
//// x: { y: T, z: T[] };
//// }
////
//// class C implements I<number> {[| |]}
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
x: { y: number; z: number[]; };

View file

@ -4,7 +4,7 @@
//// x: T;
//// }
////
//// class C implements I<number> {[| |]}
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
x: number;

View file

@ -4,7 +4,7 @@
//// x: T;
//// }
////
//// class C<T> implements I<T> {[| |]}
//// class C<T> implements I<T> {[| |]}
verify.rangeAfterCodeFix(`
x: T;

View file

@ -4,7 +4,7 @@
//// x: T;
//// }
////
//// class C<U> implements I<U> {[| |]}
//// class C<U> implements I<U> {[| |]}
verify.rangeAfterCodeFix(`
x: U;

View file

@ -7,6 +7,6 @@
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`f<T extends number>(x: T){
throw new Error('Method not implemented.');
throw new Error("Method not implemented.");
}
`);

View file

@ -8,7 +8,7 @@
verify.rangeAfterCodeFix(`
class A {
[name: string]: number;
[x: string]: number;
constructor() {
this.x = 10;