Skip to content

Commit 98055ad

Browse files
author
Benjamin Lichtman
committed
Use separate map with smaller scope to track renames
1 parent e700022 commit 98055ad

File tree

1 file changed

+35
-15
lines changed

1 file changed

+35
-15
lines changed

src/services/codefixes/convertToAsyncFunction.ts

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ namespace ts.codefix {
2525
numberOfAssignmentsOriginal: number;
2626
}
2727

28-
interface SymbolAndIdentifierAndOriginalName {
28+
interface SymbolAndIdentifier {
2929
identifier: Identifier;
3030
symbol: Symbol;
31-
originalName: string;
3231
}
3332

3433
interface Transformer {
3534
checker: TypeChecker;
3635
synthNamesMap: Map<SynthIdentifier>; // keys are the symbol id of the identifier
37-
allVarNames: SymbolAndIdentifierAndOriginalName[];
36+
allVarNames: SymbolAndIdentifier[];
3837
setOfExpressionsToReturn: Map<true>; // keys are the node ids of the expressions
3938
constIdentifiers: Identifier[];
4039
originalTypeMap: Map<Type>; // keys are the node id of the identifier
@@ -61,7 +60,7 @@ namespace ts.codefix {
6160

6261
const synthNamesMap: Map<SynthIdentifier> = createMap();
6362
const originalTypeMap: Map<Type> = createMap();
64-
const allVarNames: SymbolAndIdentifierAndOriginalName[] = [];
63+
const allVarNames: SymbolAndIdentifier[] = [];
6564
const isInJSFile = isInJavaScriptFile(functionToConvert);
6665
const setOfExpressionsToReturn = getAllPromiseExpressionsToReturn(functionToConvert, checker);
6766
const functionToConvertRenamed: FunctionLikeDeclaration = renameCollidingVarNames(functionToConvert, checker, synthNamesMap, context, setOfExpressionsToReturn, originalTypeMap, allVarNames);
@@ -158,9 +157,10 @@ namespace ts.codefix {
158157
This function collects all existing identifier names and names of identifiers that will be created in the refactor.
159158
It then checks for any collisions and renames them through getSynthesizedDeepClone
160159
*/
161-
function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map<SynthIdentifier>, context: CodeFixContextBase, setOfAllExpressionsToReturn: Map<true>, originalType: Map<Type>, allVarNames: SymbolAndIdentifierAndOriginalName[]): FunctionLikeDeclaration {
160+
function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map<SynthIdentifier>, context: CodeFixContextBase, setOfAllExpressionsToReturn: Map<true>, originalType: Map<Type>, allVarNames: SymbolAndIdentifier[]): FunctionLikeDeclaration {
162161

163162
const identsToRenameMap: Map<Identifier> = createMap(); // key is the symbol id
163+
const collidingSymbolMap: Map<Symbol[]> = createMap();
164164
forEachChild(nodeToRename, function visit(node: Node) {
165165
if (!isIdentifier(node)) {
166166
forEachChild(node, visit);
@@ -180,27 +180,31 @@ namespace ts.codefix {
180180
if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) {
181181
const firstParameter = lastCallSignature.parameters[0];
182182
const ident = isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result");
183-
const synthName = getNewNameIfConflict(ident, allVarNames);
183+
const synthName = getNewNameIfConflict(ident, collidingSymbolMap);
184184
synthNamesMap.set(symbolIdString, synthName);
185-
allVarNames.push({ identifier: synthName.identifier, symbol, originalName: ident.text });
185+
allVarNames.push({ identifier: synthName.identifier, symbol });
186+
addNameToFrequencyMap(collidingSymbolMap, ident.text, symbol);
186187
}
187188
// we only care about identifiers that are parameters and declarations (don't care about other uses)
188189
else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent))) {
189190
const originalName = node.text;
191+
const collidingSymbols = collidingSymbolMap.get(originalName);
190192

191193
// if the identifier name conflicts with a different identifier that we've already seen
192-
if (allVarNames.some(ident => ident.originalName === node.text && ident.symbol !== symbol)) {
193-
const newName = getNewNameIfConflict(node, allVarNames);
194+
if (collidingSymbols && collidingSymbols.some(prevSymbol => prevSymbol !== symbol)) {
195+
const newName = getNewNameIfConflict(node, collidingSymbolMap);
194196
identsToRenameMap.set(symbolIdString, newName.identifier);
195197
synthNamesMap.set(symbolIdString, newName);
196-
allVarNames.push({ identifier: newName.identifier, symbol, originalName });
198+
allVarNames.push({ identifier: newName.identifier, symbol });
199+
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
197200
}
198201
else {
199202
const identifier = getSynthesizedDeepClone(node);
200203
identsToRenameMap.set(symbolIdString, identifier);
201204
synthNamesMap.set(symbolIdString, { identifier, types: [], numberOfAssignmentsOriginal: allVarNames.filter(elem => elem.identifier.text === node.text).length/*, numberOfAssignmentsSynthesized: 0*/ });
202205
if ((isParameter(node.parent) && isExpressionOrCallOnTypePromise(node.parent.parent)) || isVariableDeclaration(node.parent)) {
203-
allVarNames.push({ identifier, symbol, originalName });
206+
allVarNames.push({ identifier, symbol });
207+
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
204208
}
205209
}
206210
}
@@ -243,8 +247,17 @@ namespace ts.codefix {
243247

244248
}
245249

246-
function getNewNameIfConflict(name: Identifier, allVarNames: SymbolAndIdentifierAndOriginalName[]): SynthIdentifier {
247-
const numVarsSameName = allVarNames.filter(elem => elem.originalName === name.text).length;
250+
function addNameToFrequencyMap(renamedVarNameFrequencyMap: Map<Symbol[]>, originalName: string, symbol: Symbol) {
251+
if (renamedVarNameFrequencyMap.has(originalName)) {
252+
renamedVarNameFrequencyMap.get(originalName)!.push(symbol);
253+
}
254+
else {
255+
renamedVarNameFrequencyMap.set(originalName, [symbol]);
256+
}
257+
}
258+
259+
function getNewNameIfConflict(name: Identifier, originalNames: Map<Symbol[]>): SynthIdentifier {
260+
const numVarsSameName = (originalNames.get(name.text) || []).length;
248261
const numberOfAssignmentsOriginal = 0;
249262
const identifier = numVarsSameName === 0 ? name : createIdentifier(name.text + "_" + numVarsSameName);
250263
return { identifier, types: [], numberOfAssignmentsOriginal };
@@ -289,13 +302,14 @@ namespace ts.codefix {
289302
prevArgName.numberOfAssignmentsOriginal = 2; // Try block and catch block
290303
transformer.synthNamesMap.forEach((val, key) => {
291304
if (val.identifier.text === prevArgName.identifier.text) {
292-
transformer.synthNamesMap.set(key, getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames));
305+
const newSynthName = createUniqueSynthName(prevArgName);
306+
transformer.synthNamesMap.set(key, newSynthName);
293307
}
294308
});
295309

296310
// update the constIdentifiers list
297311
if (transformer.constIdentifiers.some(elem => elem.text === prevArgName.identifier.text)) {
298-
transformer.constIdentifiers.push(getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames).identifier);
312+
transformer.constIdentifiers.push(createUniqueSynthName(prevArgName).identifier);
299313
}
300314
}
301315

@@ -321,6 +335,12 @@ namespace ts.codefix {
321335
return varDeclList ? [varDeclList, tryStatement] : [tryStatement];
322336
}
323337

338+
function createUniqueSynthName(prevArgName: SynthIdentifier) {
339+
const renamedPrevArg = createOptimisticUniqueName(prevArgName.identifier.text);
340+
const newSynthName = { identifier: renamedPrevArg, types: [], numberOfAssignmentsOriginal: 0 };
341+
return newSynthName;
342+
}
343+
324344
function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
325345
const [res, rej] = node.arguments;
326346

0 commit comments

Comments
 (0)