Skip to content

Commit 384669a

Browse files
committed
Finish addMissingConst codefix for single variable and array literal assignments
1 parent 7d08f17 commit 384669a

File tree

4 files changed

+61
-17
lines changed

4 files changed

+61
-17
lines changed

src/services/codefixes/addMissingConst.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,44 @@ namespace ts.codefix {
99
registerCodeFix({
1010
errorCodes,
1111
getCodeActions: (context) => {
12-
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start));
12+
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start, context.program));
1313
if (changes.length > 0) {
1414
return [createCodeFixAction(fixId, changes, Diagnostics.Add_const_to_unresolved_variable, fixId, Diagnostics.Add_const_to_all_unresolved_variables)];
1515
}
1616
},
1717
fixIds: [fixId],
1818
getAllCodeActions: context => {
1919
const fixedNodes = new NodeSet();
20-
return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, fixedNodes));
20+
return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, fixedNodes));
2121
},
2222
});
2323

24-
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, fixedNodes?: NodeSet<Node>) {
24+
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, program: Program, fixedNodes?: NodeSet<Node>) {
2525
const token = getTokenAtPosition(sourceFile, pos);
26-
2726
const forInitializer = findAncestor(token, node =>
28-
isForInOrOfStatement(node.parent) ? node.parent.initializer === node
29-
: isPossiblyPartOfDestructuring(node) ? false : "quit");
27+
isForInOrOfStatement(node.parent) ? node.parent.initializer === node :
28+
isPossiblyPartOfDestructuring(node) ? false : "quit"
29+
);
3030
if (forInitializer) return applyChange(changeTracker, forInitializer, sourceFile, fixedNodes);
3131

3232
const parent = token.parent;
33-
const standaloneInitializer = isExpressionStatement(parent.parent);
34-
if (standaloneInitializer) return applyChange(changeTracker, parent, sourceFile, fixedNodes);
33+
if (isBinaryExpression(parent) && isExpressionStatement(parent.parent)) {
34+
return applyChange(changeTracker, token, sourceFile, fixedNodes);
35+
}
3536

36-
const arrayLiteralInitializer = isArrayLiteralExpression(token.parent);
37-
if (arrayLiteralInitializer) {
38-
const availableIdentifiers: string[] = []; // TODO: where to get/gather this information from?
39-
const noIdentifiersDeclared = parent.forEachChild(node => availableIdentifiers.indexOf(node.getFullText()) < 0);
40-
if (!noIdentifiersDeclared) return;
37+
if (isArrayLiteralExpression(parent)) {
38+
const checker = program.getTypeChecker();
39+
if (!every(parent.elements, element => arrayElementCouldBeVariableDeclaration(element, checker))) {
40+
return;
41+
}
4142

4243
return applyChange(changeTracker, parent, sourceFile, fixedNodes);
4344
}
4445
}
4546

4647
function applyChange(changeTracker: textChanges.ChangeTracker, initializer: Node, sourceFile: SourceFile, fixedNodes?: NodeSet<Node>) {
4748
if (!fixedNodes || fixedNodes.tryAdd(initializer)) {
48-
changeTracker.insertNodeBefore(sourceFile, initializer, createToken(SyntaxKind.ConstKeyword));
49+
changeTracker.insertModifierBefore(sourceFile, SyntaxKind.ConstKeyword, initializer);
4950
}
5051
}
5152

@@ -61,4 +62,12 @@ namespace ts.codefix {
6162
return false;
6263
}
6364
}
65+
66+
function arrayElementCouldBeVariableDeclaration(expression: Expression, checker: TypeChecker) {
67+
const identifier =
68+
isIdentifier(expression) ? expression :
69+
isAssignmentExpression(expression, /*excludeCompoundAssignment*/ true) && isIdentifier(expression.left) ? expression.left :
70+
undefined;
71+
return !!identifier && !checker.getSymbolAtLocation(identifier);
72+
}
6473
}

src/services/textChanges.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,6 @@ namespace ts.textChanges {
425425
else if (isStringLiteral(before) && isImportDeclaration(before.parent) || isNamedImports(before)) {
426426
return { suffix: ", " };
427427
}
428-
else if (isForInitializer(before)) {
429-
return { suffix: " " };
430-
}
431428
return Debug.failBadSyntaxKind(before); // We haven't handled this kind of node yet -- add it
432429
}
433430

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////a = () => {
4+
//// x = 0;
5+
//// [y] = [1];
6+
//// weirdlyIndented = 2;
7+
////};
8+
////b = 3;
9+
10+
verify.codeFixAll({
11+
fixId: "addMissingConst",
12+
fixAllDescription: "Add 'const' to all unresolved variables",
13+
newFileContent: `const a = () => {
14+
const x = 0;
15+
const [y] = [1];
16+
const weirdlyIndented = 2;
17+
};
18+
const b = 3;`
19+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////a = () => {
4+
//// for (x in []) {
5+
//// y = 0;
6+
//// }
7+
////};
8+
////b = 3;
9+
10+
verify.codeFixAll({
11+
fixId: "addMissingConst",
12+
fixAllDescription: "Add 'const' to all unresolved variables",
13+
newFileContent: `const a = () => {
14+
for (const x in []) {
15+
const y = 0;
16+
}
17+
};
18+
const b = 3;`
19+
});

0 commit comments

Comments
 (0)