handle well-known computed property/method names

This commit is contained in:
Arthur Ozga
2016-12-07 17:00:20 -08:00
parent c511aea581
commit 5cd0ea3741
7 changed files with 74 additions and 91 deletions

View File

@@ -20,15 +20,17 @@ namespace ts.codefix {
}
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
const name = symbol.getName();
// const name = symbol.getName();
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
const declarations = symbol.getDeclarations();
if (!(declarations && declarations.length)) {
return "";
}
const node = declarations[0];
const visibility = getVisibilityPrefix(getModifierFlags(node));
switch (node.kind) {
const declaration = declarations[0] as Declaration;
const name = declaration.name.getText();
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
@@ -68,14 +70,15 @@ namespace ts.codefix {
bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
}
else {
bodySig = createBodyDeclarationSignatureWithAnyTypes(declarations as SignatureDeclaration[], signatures, enclosingDeclaration, checker);
Debug.assert(declarations.length === signatures.length);
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
}
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
return result;
case SyntaxKind.ComputedPropertyName:
if (hasDynamicName(node)) {
if (hasDynamicName(declaration)) {
return "";
}
throw new Error("Not implemented, computed property name.");
@@ -87,22 +90,25 @@ namespace ts.codefix {
}
}
function createBodyDeclarationSignatureWithAnyTypes(signatureDecls: SignatureDeclaration[], signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
Debug.assert(signatureDecls.length === signatures.length);
function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration;
newSignatureDeclaration.parent = enclosingDeclaration;
newSignatureDeclaration.name = signatureDecls[0].name;
newSignatureDeclaration.name = signatures[0].getDeclaration().name;
let maxArgs = -1, maxArgsIndex = 0;
let maxArgs = -1;
let minArgumentCount = signatures[0].minArgumentCount;
let hasRestParameter = false;
let allMaxArgsAreRest = true;
for (let i = 0; i < signatures.length; i++) {
const sig = signatures[i];
minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount);
if (sig.parameters.length > maxArgs) {
maxArgs = sig.parameters.length;
maxArgsIndex = i;
allMaxArgsAreRest = sig.hasRestParameter;
}
else if (sig.parameters.length === maxArgs) {
allMaxArgsAreRest = allMaxArgsAreRest && sig.hasRestParameter;
}
hasRestParameter = hasRestParameter || sig.hasRestParameter;
}
@@ -120,10 +126,6 @@ namespace ts.codefix {
if (hasRestParameter) {
lastParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
let allMaxArgsAreRest = true;
for (const sig of signatures) {
allMaxArgsAreRest = allMaxArgsAreRest && sig.parameters[maxArgs - 1] && sig.hasRestParameter;
}
if (!allMaxArgsAreRest) {
const newParameter = createParameterDeclaration(maxArgs - 1, minArgumentCount, newSignatureDeclaration);
newSignatureDeclaration.parameters.push(newParameter);
@@ -137,13 +139,13 @@ namespace ts.codefix {
return checker.getSignatureFromDeclaration(newSignatureDeclaration);
function createParameterDeclaration(index: number, minArgCount: number, enclosingSignature: SignatureDeclaration): ParameterDeclaration {
function createParameterDeclaration(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration {
const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
newParameter.symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, "arg" + index);
newParameter.symbol.valueDeclaration = newParameter;
newParameter.symbol.declarations = [newParameter];
newParameter.type = anyTypeNode;
newParameter.parent = enclosingSignature;
newParameter.parent = enclosingSignatureDeclaration;
if (index >= minArgCount) {
newParameter.questionToken = optionalToken;
}

View File

@@ -12,7 +12,7 @@ verify.rangeAfterCodeFix(`
f(a: number, b: string): boolean;
f(a: string, b: number): Function;
f(a: string): Function;
f(arg0: any, arg1? any) {
throw new Error("Method not implemented");
f(arg0: any, arg1?: any) {
throw new Error('Method not implemented.');
}
`);

View File

@@ -1,18 +0,0 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// f1():string;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
}
`);

View File

@@ -1,18 +0,0 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// f1():string;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
}
`);

View File

@@ -1,18 +0,0 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// f1():string;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
}
`);

View File

@@ -1,18 +0,0 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// f1():string;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
}
`);

View File

@@ -0,0 +1,53 @@
/// <reference path='fourslash.ts' />
// @lib: es2017
//// interface I<Species> {
//// [Symbol.hasInstance](o: any): boolean;
//// [Symbol.isConcatSpreadable]: boolean;
//// [Symbol.iterator](): Iterator<this>;
//// [Symbol.match]: boolean;
//// [Symbol.replace](...args);
//// [Symbol.search](str: string): number;
//// [Symbol.species](): Species;
//// [Symbol.split](str: string, limit?: number): string[];
//// [Symbol.toPrimitive](hint: "number"): number;
//// [Symbol.toPrimitive](hint: "default"): number;
//// [Symbol.toPrimitive](hint: "string"): string;
//// [Symbol.toStringTag]: string;
//// [Symbol.unscopables]: any;
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
[Symbol.hasInstance](o: any): boolean {
throw new Error('Method not implemented.');
}
[Symbol.isConcatSpreadable]: boolean;
[Symbol.iterator]() {
throw new Error('Method not implemented.');
}
[Symbol.match]: boolean;
[Symbol.replace](...args: {}) {
throw new Error('Method not implemented.');
}
[Symbol.search](str: string): number {
throw new Error('Method not implemented.');
}
[Symbol.species](): number {
throw new Error('Method not implemented.');
}
[Symbol.split](str: string, limit?: number): {} {
throw new Error('Method not implemented.');
}
[Symbol.toPrimitive](hint: "number"): number;
[Symbol.toPrimitive](hint: "default"): number;
[Symbol.toPrimitive](hint: "string"): string;
[Symbol.toPrimitive](arg0: any) {
throw new Error('Method not implemented.');
}
[Symbol.toStringTag]: string;
[Symbol.unscopables]: any;
`);