Skip to content

Commit 5cd0ea3

Browse files
author
Arthur Ozga
committed
handle well-known computed property/method names
1 parent c511aea commit 5cd0ea3

7 files changed

+74
-91
lines changed

src/services/codefixes/helpers.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ namespace ts.codefix {
2020
}
2121

2222
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
23-
const name = symbol.getName();
23+
// const name = symbol.getName();
2424
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
2525
const declarations = symbol.getDeclarations();
2626
if (!(declarations && declarations.length)) {
2727
return "";
2828
}
29-
const node = declarations[0];
30-
const visibility = getVisibilityPrefix(getModifierFlags(node));
31-
switch (node.kind) {
29+
30+
const declaration = declarations[0] as Declaration;
31+
const name = declaration.name.getText();
32+
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
33+
switch (declaration.kind) {
3234
case SyntaxKind.GetAccessor:
3335
case SyntaxKind.SetAccessor:
3436
case SyntaxKind.PropertySignature:
@@ -68,14 +70,15 @@ namespace ts.codefix {
6870
bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
6971
}
7072
else {
71-
bodySig = createBodyDeclarationSignatureWithAnyTypes(declarations as SignatureDeclaration[], signatures, enclosingDeclaration, checker);
73+
Debug.assert(declarations.length === signatures.length);
74+
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
7275
}
7376
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
7477
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
7578

7679
return result;
7780
case SyntaxKind.ComputedPropertyName:
78-
if (hasDynamicName(node)) {
81+
if (hasDynamicName(declaration)) {
7982
return "";
8083
}
8184
throw new Error("Not implemented, computed property name.");
@@ -87,22 +90,25 @@ namespace ts.codefix {
8790
}
8891
}
8992

90-
function createBodyDeclarationSignatureWithAnyTypes(signatureDecls: SignatureDeclaration[], signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
91-
Debug.assert(signatureDecls.length === signatures.length);
93+
function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
9294

9395
const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration;
9496
newSignatureDeclaration.parent = enclosingDeclaration;
95-
newSignatureDeclaration.name = signatureDecls[0].name;
97+
newSignatureDeclaration.name = signatures[0].getDeclaration().name;
9698

97-
let maxArgs = -1, maxArgsIndex = 0;
99+
let maxArgs = -1;
98100
let minArgumentCount = signatures[0].minArgumentCount;
99101
let hasRestParameter = false;
102+
let allMaxArgsAreRest = true;
100103
for (let i = 0; i < signatures.length; i++) {
101104
const sig = signatures[i];
102105
minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount);
103106
if (sig.parameters.length > maxArgs) {
104107
maxArgs = sig.parameters.length;
105-
maxArgsIndex = i;
108+
allMaxArgsAreRest = sig.hasRestParameter;
109+
}
110+
else if (sig.parameters.length === maxArgs) {
111+
allMaxArgsAreRest = allMaxArgsAreRest && sig.hasRestParameter;
106112
}
107113
hasRestParameter = hasRestParameter || sig.hasRestParameter;
108114
}
@@ -120,10 +126,6 @@ namespace ts.codefix {
120126
if (hasRestParameter) {
121127
lastParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
122128

123-
let allMaxArgsAreRest = true;
124-
for (const sig of signatures) {
125-
allMaxArgsAreRest = allMaxArgsAreRest && sig.parameters[maxArgs - 1] && sig.hasRestParameter;
126-
}
127129
if (!allMaxArgsAreRest) {
128130
const newParameter = createParameterDeclaration(maxArgs - 1, minArgumentCount, newSignatureDeclaration);
129131
newSignatureDeclaration.parameters.push(newParameter);
@@ -137,13 +139,13 @@ namespace ts.codefix {
137139

138140
return checker.getSignatureFromDeclaration(newSignatureDeclaration);
139141

140-
function createParameterDeclaration(index: number, minArgCount: number, enclosingSignature: SignatureDeclaration): ParameterDeclaration {
142+
function createParameterDeclaration(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration {
141143
const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
142144
newParameter.symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, "arg" + index);
143145
newParameter.symbol.valueDeclaration = newParameter;
144146
newParameter.symbol.declarations = [newParameter];
145147
newParameter.type = anyTypeNode;
146-
newParameter.parent = enclosingSignature;
148+
newParameter.parent = enclosingSignatureDeclaration;
147149
if (index >= minArgCount) {
148150
newParameter.questionToken = optionalToken;
149151
}

tests/cases/fourslash/codeFixClassExtendsAbstractMethod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ verify.rangeAfterCodeFix(`
1212
f(a: number, b: string): boolean;
1313
f(a: string, b: number): Function;
1414
f(a: string): Function;
15-
f(arg0: any, arg1? any) {
16-
throw new Error("Method not implemented");
15+
f(arg0: any, arg1?: any) {
16+
throw new Error('Method not implemented.');
1717
}
1818
`);

tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (3).ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (4).ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (5).ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (6).ts

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @lib: es2017
4+
5+
//// interface I<Species> {
6+
//// [Symbol.hasInstance](o: any): boolean;
7+
//// [Symbol.isConcatSpreadable]: boolean;
8+
//// [Symbol.iterator](): Iterator<this>;
9+
//// [Symbol.match]: boolean;
10+
//// [Symbol.replace](...args);
11+
//// [Symbol.search](str: string): number;
12+
//// [Symbol.species](): Species;
13+
//// [Symbol.split](str: string, limit?: number): string[];
14+
//// [Symbol.toPrimitive](hint: "number"): number;
15+
//// [Symbol.toPrimitive](hint: "default"): number;
16+
//// [Symbol.toPrimitive](hint: "string"): string;
17+
//// [Symbol.toStringTag]: string;
18+
//// [Symbol.unscopables]: any;
19+
//// }
20+
////
21+
//// class C implements I<number> {[| |]}
22+
23+
24+
verify.rangeAfterCodeFix(`
25+
[Symbol.hasInstance](o: any): boolean {
26+
throw new Error('Method not implemented.');
27+
}
28+
[Symbol.isConcatSpreadable]: boolean;
29+
[Symbol.iterator]() {
30+
throw new Error('Method not implemented.');
31+
}
32+
[Symbol.match]: boolean;
33+
[Symbol.replace](...args: {}) {
34+
throw new Error('Method not implemented.');
35+
}
36+
[Symbol.search](str: string): number {
37+
throw new Error('Method not implemented.');
38+
}
39+
[Symbol.species](): number {
40+
throw new Error('Method not implemented.');
41+
}
42+
[Symbol.split](str: string, limit?: number): {} {
43+
throw new Error('Method not implemented.');
44+
}
45+
[Symbol.toPrimitive](hint: "number"): number;
46+
[Symbol.toPrimitive](hint: "default"): number;
47+
[Symbol.toPrimitive](hint: "string"): string;
48+
[Symbol.toPrimitive](arg0: any) {
49+
throw new Error('Method not implemented.');
50+
}
51+
[Symbol.toStringTag]: string;
52+
[Symbol.unscopables]: any;
53+
`);

0 commit comments

Comments
 (0)