Skip to content

Commit 1a8f333

Browse files
author
Andy Hanson
committed
codeFixInferFromUsage: Avoid duplicate fix for variable declaration
1 parent c3df6ed commit 1a8f333

File tree

3 files changed

+20
-8
lines changed

3 files changed

+20
-8
lines changed

src/services/codefixes/inferFromUsage.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ namespace ts.codefix {
3232

3333
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
3434
let declaration!: Declaration;
35-
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken); });
35+
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeenseen*/ returnTrue); });
3636
return changes.length === 0 ? undefined
3737
: [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), getNameOfDeclaration(declaration).getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)];
3838
},
3939
fixIds: [fixId],
4040
getAllCodeActions(context) {
4141
const { sourceFile, program, cancellationToken } = context;
42-
const seenFunctions = createMap<true>();
42+
const markSeen = nodeSeenTracker();
4343
return codeFixAll(context, errorCodes, (changes, err) => {
44-
doChange(changes, sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, seenFunctions);
44+
doChange(changes, sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, markSeen);
4545
});
4646
},
4747
});
@@ -57,7 +57,7 @@ namespace ts.codefix {
5757
}
5858
}
5959

60-
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, seenFunctions?: Map<true>): Declaration | undefined {
60+
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker): Declaration | undefined {
6161
if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken) {
6262
return undefined;
6363
}
@@ -67,18 +67,19 @@ namespace ts.codefix {
6767
// Variable and Property declarations
6868
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
6969
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
70-
if (isVariableDeclaration(parent) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location
70+
if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location
7171
annotateVariableDeclaration(changes, sourceFile, parent, program, cancellationToken);
7272
return parent;
7373
}
7474
return undefined;
7575

7676
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
7777
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
78-
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration)) {
78+
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) {
7979
annotateVariableDeclaration(changes, sourceFile, symbol.valueDeclaration, program, cancellationToken);
8080
return symbol.valueDeclaration;
8181
}
82+
return undefined;
8283
}
8384
}
8485

@@ -96,7 +97,7 @@ namespace ts.codefix {
9697
}
9798
// falls through
9899
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
99-
if (!seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction))) {
100+
if (markSeen(containingFunction)) {
100101
const param = cast(parent, isParameter);
101102
annotateParameters(changes, param, containingFunction, sourceFile, program, cancellationToken);
102103
return param;

src/services/utilities.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,8 @@ namespace ts {
11881188
}
11891189

11901190
/** Returns `true` the first time it encounters a node and `false` afterwards. */
1191-
export function nodeSeenTracker<T extends Node>(): (node: T) => boolean {
1191+
export type NodeSeenTracker<T = Node> = (node: T) => boolean;
1192+
export function nodeSeenTracker<T extends Node>(): NodeSeenTracker<T> {
11921193
const seen: true[] = [];
11931194
return node => {
11941195
const id = getNodeId(node);

tests/cases/fourslash/codeFixInferFromUsage_all.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
////function g(z) {
1111
//// return z * 2;
1212
////}
13+
////
14+
////let x = null;
15+
////function h() {
16+
//// if (!x) x = 2;
17+
////}
1318

1419
verify.codeFixAll({
1520
fixId: "inferFromUsage",
@@ -22,5 +27,10 @@ verify.codeFixAll({
2227
2328
function g(z: number) {
2429
return z * 2;
30+
}
31+
32+
let x: number = null;
33+
function h() {
34+
if (!x) x = 2;
2535
}`,
2636
});

0 commit comments

Comments
 (0)