respond to comments

This commit is contained in:
Arthur Ozga 2017-03-21 22:54:06 -07:00
parent 67587cbbbd
commit 5b739cf78c
13 changed files with 180 additions and 68 deletions

View file

@ -106,9 +106,9 @@ namespace ts {
getParameterType: getTypeAtPosition,
getReturnTypeOfSignature,
getNonNullableType,
createTypeNode,
createIndexSignatureFromIndexInfo,
createSignatureParts,
typeToTypeNode,
indexInfoToIndexSignatureDeclaration,
signatureToSignatureDeclaration,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? getSymbolsInScope(location, meaning) : [];
@ -2196,8 +2196,8 @@ namespace ts {
return undefined;
}
const constraint = createTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration);
const defaultParameter = createTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration);
const constraint = typeToTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration);
const defaultParameter = typeToTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration);
const name = symbolToString(type.symbol);
return createTypeParameterDeclaration(name, constraint, defaultParameter);
@ -2206,7 +2206,7 @@ namespace ts {
function createParameterDeclarationFromSymbol(parameterSymbol: Symbol, enclosingDeclaration: Node): ParameterDeclaration {
const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration;
const parameterType = getTypeOfSymbol(parameterSymbol);
const parameterTypeNode = createTypeNode(parameterType, enclosingDeclaration);
const parameterTypeNode = typeToTypeNode(parameterType, enclosingDeclaration);
// TODO: how should we clone members/modifiers?
// TODO: check initializer accessibility correctly.
const parameterNode = createParameter(
@ -2220,32 +2220,35 @@ namespace ts {
return parameterNode;
}
function createSignatureParts(signature: Signature, enclosingDeclaration: Node): SignatureParts {
return {
typeParameters: signature.typeParameters && signature.typeParameters.map(parameter => createTypeParameterDeclarationFromType(parameter,enclosingDeclaration)),
parameters: signature.parameters.map(parameter => createParameterDeclarationFromSymbol(parameter,enclosingDeclaration)),
type: createTypeNodeExceptAny(getReturnTypeOfSignature(signature))
}
function signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => createTypeParameterDeclarationFromType(parameter, enclosingDeclaration));
const parameters = signature.parameters.map(parameter => createParameterDeclarationFromSymbol(parameter, enclosingDeclaration));
const type = createTypeNodeExceptAny(getReturnTypeOfSignature(signature));
return createSignatureDeclaration(kind, typeParameters, parameters, type);
function createTypeNodeExceptAny(type: Type): TypeNode | undefined {
const typeNode = createTypeNode(type, enclosingDeclaration);
const typeNode = typeToTypeNode(type, enclosingDeclaration);
return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined;
}
}
function createTypeNode(type: Type, enclosingDeclaration: Node): TypeNode {
let undefinedArgumentIsError = true;
// function typeToDisplayParts
function typeToTypeNode(type: Type, enclosingDeclaration: Node, returnNodeOnError?: boolean): TypeNode {
let encounteredError = false;
let inObjectTypeLiteral = false;
let checkAlias = true;
let symbolStack: Symbol[] = undefined;
const result = createTypeNodeWorker(type);
return encounteredError ? undefined: result;
// returnNodeOnError = true; // TODO: unset.
return encounteredError && !returnNodeOnError ? undefined: result;
function createTypeNodeWorker(type: Type): TypeNode {
if (!type) {
if (undefinedArgumentIsError) { encounteredError = true; }
encounteredError = true;
return undefined;
}
@ -2364,7 +2367,7 @@ namespace ts {
const typeParameter = getTypeParameterFromMappedType(<MappedType>type);
const typeParameterNode = createTypeParameterDeclarationFromType(typeParameter, enclosingDeclaration);
const templateTypeNode = createTypeNode(getTemplateTypeFromMappedType(<MappedType>type), enclosingDeclaration);
const templateTypeNode = typeToTypeNode(getTemplateTypeFromMappedType(<MappedType>type), enclosingDeclaration);
const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
@ -2438,13 +2441,11 @@ namespace ts {
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const signature = resolved.callSignatures[0];
const signatureParts = createSignatureParts(signature, enclosingDeclaration);
return createSignatureDeclaration<FunctionTypeNode>(SyntaxKind.FunctionType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
return <FunctionTypeNode>signatureToSignatureDeclaration(signature, SyntaxKind.FunctionType, enclosingDeclaration);
}
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
const signature = resolved.constructSignatures[0];
const signatureParts = createSignatureParts(signature, enclosingDeclaration);
return createSignatureDeclaration<ConstructorTypeNode>(SyntaxKind.ConstructorType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
return <ConstructorTypeNode>signatureToSignatureDeclaration(signature, SyntaxKind.ConstructorType, enclosingDeclaration);
}
}
@ -2520,18 +2521,16 @@ namespace ts {
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
const typeElements: TypeElement[] = [];
for (const signature of resolvedType.callSignatures) {
const signatureParts = createSignatureParts(signature, enclosingDeclaration);
typeElements.push(createSignatureDeclaration<CallSignatureDeclaration>(SyntaxKind.CallSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclaration(signature, SyntaxKind.CallSignature, enclosingDeclaration));
}
for (const signature of resolvedType.constructSignatures) {
const signatureParts = createSignatureParts(signature, enclosingDeclaration);
typeElements.push(createSignatureDeclaration<ConstructSignatureDeclaration>(SyntaxKind.ConstructSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclaration(signature, SyntaxKind.ConstructSignature, enclosingDeclaration));
}
if (resolvedType.stringIndexInfo) {
typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration));
typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration));
}
if (resolvedType.numberIndexInfo) {
typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration));
typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration));
}
const properties = resolvedType.properties;
@ -2550,8 +2549,8 @@ namespace ts {
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) {
const signatureParts = createSignatureParts(signature, enclosingDeclaration);
const methodDeclaration = createSignatureDeclaration<MethodSignature>(SyntaxKind.MethodSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type, propertyName, optionalToken);
const methodDeclaration = <MethodSignature>signatureToSignatureDeclaration(signature, SyntaxKind.MethodSignature, enclosingDeclaration);
methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration);
}
@ -2571,7 +2570,6 @@ namespace ts {
function createNameFromSymbol(symbol: Symbol): EntityName;
function createNameFromSymbol(symbol: Symbol): EntityName {
let parentSymbol: Symbol;
symbol; enclosingDeclaration;
let meaning: SymbolFlags;
// Get qualified name if the symbol is not a type parameter
@ -2580,18 +2578,49 @@ namespace ts {
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
if (!isTypeParameter && enclosingDeclaration) {
chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true);
// TODO: check whether type pointed to by symbol requires type arguments to be printed.
Debug.assert(chain && chain.length > 0);
}
else {
chain = [symbol];
}
parentSymbol = undefined;
const result = createEntityNameFromSymbolChain(chain, chain.length - 1);
return result;
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
Debug.assert(chain && 0 <= index && index < chain.length);
const identifier = createIdentifier(getNameOfSymbol(chain[index]));
// const parentIndex = index - 1;
const symbol = chain[index];
let typeParameterString = "";
if(index > 0) {
// TODO: is the parentSymbol wrong?
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) {
encounteredError = true;
const writer = getSingleLineStringWriter();
const displayBuilder = getSymbolDisplayBuilder();
displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0);
typeParameterString = writer.string();
releaseStringWriter(writer);
}
}
const symbolName = getNameOfSymbol(symbol);
const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName;
let identifier = createIdentifier(symbolNameWithTypeParameters);
return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
}
@ -2628,10 +2657,31 @@ namespace ts {
}
}
}
function getNameOfSymbol(symbol: Symbol): string {
if (symbol.declarations && symbol.declarations.length) {
const declaration = symbol.declarations[0];
if (declaration.name) {
return declarationNameToString(declaration.name);
}
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
}
encounteredError = true;
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
}
return symbol.name;
}
}
}
function createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration {
function indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration {
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
const name = getNameFromIndexInfo(indexInfo);
@ -2643,7 +2693,7 @@ namespace ts {
/*questionToken*/ undefined,
indexerTypeNode,
/*initializer*/ undefined);
const typeNode = createTypeNode(indexInfo.type, enclosingDeclaration);
const typeNode = typeToTypeNode(indexInfo.type, enclosingDeclaration);
return createIndexSignatureDeclaration(
[indexingParameter],
typeNode,

View file

@ -1067,9 +1067,6 @@ namespace ts {
/** Does nothing. */
export function noop(): void {}
/** Returns its first argument. */
export function identity<X>(x: X): X { return x; }
/** Throws an error because a function is not implemented. */
export function notImplemented(): never {
throw new Error("Not implemented");

View file

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

View file

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

View file

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

View file

@ -2473,11 +2473,11 @@ namespace ts {
getNonNullableType(type: Type): Type;
/** Note that the resulting nodes cannot be checked. */
createTypeNode(type: Type, enclosingDeclaration: Node): TypeNode;
typeToTypeNode(type: Type, enclosingDeclaration: Node): TypeNode;
/** Note that the resulting nodes cannot be checked. */
createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration;
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration;
/** Note that the resulting nodes cannot be checked. */
createSignatureParts(signature: Signature, enclosingDeclaration: Node): SignatureParts;
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node): SignatureDeclaration;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolAtLocation(node: Node): Symbol;

View file

@ -744,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;
}
@ -3735,7 +3735,7 @@ namespace ts {
* of a TypeNode.
*/
export function isTypeNode(node: Node): node is TypeNode {
return isTypeNodeKind(node.kind);
return node && isTypeNodeKind(node.kind) && (!node.parent || isPartOfTypeNode(node));
}
// Binding patterns

View file

@ -38,7 +38,7 @@ namespace ts.codefix {
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeNode = checker.createTypeNode(widenedType, classDeclaration) || typeNode;
typeNode = checker.typeToTypeNode(widenedType, classDeclaration) || typeNode;
}
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);

View file

@ -53,7 +53,7 @@ namespace ts.codefix {
if (!indexInfoOfKind) {
return;
}
const newIndexSignatureDeclaration = checker.createIndexSignatureFromIndexInfo(indexInfoOfKind, kind, classDeclaration);
const newIndexSignatureDeclaration = checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration);
newNodes.push(newIndexSignatureDeclaration);
}

View file

@ -64,7 +64,7 @@ namespace ts.codefix {
const declaration = declarations[0] as Declaration;
const name = declaration.name ? getSynthesizedDeepClone(declaration.name) as PropertyName : undefined;
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
const modifiers = visibilityModifier ? [visibilityModifier] : undefined;
const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined;
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
switch (declaration.kind) {
@ -72,7 +72,7 @@ namespace ts.codefix {
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
const typeNode = checker.createTypeNode(type, enclosingDeclaration);
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration);
const property = createProperty(
/*decorators*/undefined,
modifiers,
@ -99,30 +99,32 @@ namespace ts.codefix {
if (declarations.length === 1) {
Debug.assert(signatures.length === 1);
const signature = signatures[0];
const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration);
return createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type);
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration;
signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
signatureDeclaration.body = createStubbedMethodBody();
return signatureDeclaration;
}
let signatureDeclarations = [];
for (let i = 0; i < signatures.length; i++) {
const signature = signatures[i];
const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration);
signatureDeclarations.push(createMethod(
/*decorators*/ undefined,
modifiers,
/*asteriskToken*/ undefined,
name,
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
signatureParts.typeParameters,
signatureParts.parameters,
signatureParts.type,
/*body*/undefined));
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration;
signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
signatureDeclarations.push(signatureDeclaration);
}
if (declarations.length > signatures.length) {
let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration);
signatureDeclarations.push(createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type));
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration;
signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
signatureDeclaration.body = createStubbedMethodBody();
signatureDeclarations.push(signatureDeclaration);
}
else {
Debug.assert(declarations.length === signatures.length);
@ -195,9 +197,9 @@ namespace ts.codefix {
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
return createMethod(
/*decorators*/undefined,
/*decorators*/ undefined,
modifiers,
/*asteriskToken*/undefined,
/*asteriskToken*/ undefined,
name,
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
typeParameters,

View file

@ -0,0 +1,33 @@
/// <reference path='fourslash.ts' />
class A {
foo() {
return class { x: number; }
}
bar() {
return new class { x: number; }
}
}
class B<X> {
foo() {
return class {
x: X;
}
}
}
class D extends A { }
verify.rangeAfterCodeFix(`
f(a: number, b: string): boolean;
f(a: number, b: string): this;
f(a: string, b: number): Function;
f(a: string): Function;
f(a: any, b?: any) {
throw new Error("Method not implemented.");
}
foo(): number {
throw new Error("Method not implemented.");
}
`);

View file

@ -0,0 +1,20 @@
/// <reference path='fourslash.ts' />
//// class A {
//// foo() {
//// return class { x: number; }
//// }
//// bar() {
//// return new class { x: number; }
//// }
//// }
//// class C implements A {[| |]}
verify.rangeAfterCodeFix(`
foo() {
throw new Error("Method not implemented.");
}
bar() {
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;
`);