@zzzen/pyright-internal 1.2.0-dev.20230212 → 1.2.0-dev.20230226

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/analyzer/backgroundAnalysisProgram.d.ts +1 -0
  2. package/dist/analyzer/backgroundAnalysisProgram.js +5 -0
  3. package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
  4. package/dist/analyzer/binder.js +9 -1
  5. package/dist/analyzer/binder.js.map +1 -1
  6. package/dist/analyzer/checker.js +12 -6
  7. package/dist/analyzer/checker.js.map +1 -1
  8. package/dist/analyzer/codeFlowEngine.js +1 -1
  9. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  10. package/dist/analyzer/commentUtils.d.ts +6 -1
  11. package/dist/analyzer/commentUtils.js +100 -25
  12. package/dist/analyzer/commentUtils.js.map +1 -1
  13. package/dist/analyzer/constraintSolver.js +0 -10
  14. package/dist/analyzer/constraintSolver.js.map +1 -1
  15. package/dist/analyzer/declaration.d.ts +2 -0
  16. package/dist/analyzer/declaration.js.map +1 -1
  17. package/dist/analyzer/importResolver.d.ts +3 -2
  18. package/dist/analyzer/importResolver.js +28 -19
  19. package/dist/analyzer/importResolver.js.map +1 -1
  20. package/dist/analyzer/importStatementUtils.d.ts +1 -0
  21. package/dist/analyzer/importStatementUtils.js +14 -1
  22. package/dist/analyzer/importStatementUtils.js.map +1 -1
  23. package/dist/analyzer/parseTreeUtils.d.ts +5 -2
  24. package/dist/analyzer/parseTreeUtils.js +21 -3
  25. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  26. package/dist/analyzer/patternMatching.d.ts +1 -0
  27. package/dist/analyzer/patternMatching.js +54 -6
  28. package/dist/analyzer/patternMatching.js.map +1 -1
  29. package/dist/analyzer/program.d.ts +11 -4
  30. package/dist/analyzer/program.js +122 -25
  31. package/dist/analyzer/program.js.map +1 -1
  32. package/dist/analyzer/properties.js +5 -1
  33. package/dist/analyzer/properties.js.map +1 -1
  34. package/dist/analyzer/protocols.js +4 -3
  35. package/dist/analyzer/protocols.js.map +1 -1
  36. package/dist/analyzer/service.d.ts +7 -6
  37. package/dist/analyzer/service.js +31 -39
  38. package/dist/analyzer/service.js.map +1 -1
  39. package/dist/analyzer/sourceFile.d.ts +4 -0
  40. package/dist/analyzer/sourceFile.js +85 -16
  41. package/dist/analyzer/sourceFile.js.map +1 -1
  42. package/dist/analyzer/typeEvaluator.js +127 -76
  43. package/dist/analyzer/typeEvaluator.js.map +1 -1
  44. package/dist/backgroundAnalysisBase.d.ts +2 -2
  45. package/dist/backgroundAnalysisBase.js +21 -8
  46. package/dist/backgroundAnalysisBase.js.map +1 -1
  47. package/dist/backgroundThreadBase.js +1 -0
  48. package/dist/backgroundThreadBase.js.map +1 -1
  49. package/dist/commands/commandController.js +1 -0
  50. package/dist/commands/commandController.js.map +1 -1
  51. package/dist/commands/quickActionCommand.js +2 -2
  52. package/dist/commands/quickActionCommand.js.map +1 -1
  53. package/dist/common/cancellationUtils.d.ts +18 -2
  54. package/dist/common/cancellationUtils.js +80 -3
  55. package/dist/common/cancellationUtils.js.map +1 -1
  56. package/dist/common/commandLineOptions.d.ts +2 -0
  57. package/dist/common/commandLineOptions.js.map +1 -1
  58. package/dist/common/configOptions.d.ts +3 -0
  59. package/dist/common/configOptions.js +10 -1
  60. package/dist/common/configOptions.js.map +1 -1
  61. package/dist/common/core.d.ts +2 -0
  62. package/dist/common/core.js +9 -1
  63. package/dist/common/core.js.map +1 -1
  64. package/dist/common/diagnostic.d.ts +15 -3
  65. package/dist/common/diagnostic.js +13 -4
  66. package/dist/common/diagnostic.js.map +1 -1
  67. package/dist/common/editAction.d.ts +1 -0
  68. package/dist/common/editAction.js +8 -0
  69. package/dist/common/editAction.js.map +1 -1
  70. package/dist/common/extensibility.d.ts +36 -12
  71. package/dist/common/extensibility.js +63 -18
  72. package/dist/common/extensibility.js.map +1 -1
  73. package/dist/common/fileBasedCancellationUtils.d.ts +0 -1
  74. package/dist/common/fileBasedCancellationUtils.js +7 -81
  75. package/dist/common/fileBasedCancellationUtils.js.map +1 -1
  76. package/dist/common/pathUtils.d.ts +3 -0
  77. package/dist/common/pathUtils.js +18 -0
  78. package/dist/common/pathUtils.js.map +1 -1
  79. package/dist/common/textEditTracker.d.ts +37 -0
  80. package/dist/common/textEditTracker.js +301 -0
  81. package/dist/common/textEditTracker.js.map +1 -0
  82. package/dist/common/workspaceEditUtils.d.ts +14 -8
  83. package/dist/common/workspaceEditUtils.js +115 -59
  84. package/dist/common/workspaceEditUtils.js.map +1 -1
  85. package/dist/languageServerBase.d.ts +3 -0
  86. package/dist/languageServerBase.js +93 -4
  87. package/dist/languageServerBase.js.map +1 -1
  88. package/dist/languageService/analyzerServiceExecutor.js +1 -0
  89. package/dist/languageService/analyzerServiceExecutor.js.map +1 -1
  90. package/dist/languageService/codeActionProvider.js +1 -1
  91. package/dist/languageService/codeActionProvider.js.map +1 -1
  92. package/dist/languageService/completionProvider.js +3 -3
  93. package/dist/languageService/completionProvider.js.map +1 -1
  94. package/dist/languageService/definitionProvider.js +1 -1
  95. package/dist/languageService/definitionProvider.js.map +1 -1
  96. package/dist/languageService/documentSymbolCollector.js +1 -1
  97. package/dist/languageService/documentSymbolCollector.js.map +1 -1
  98. package/dist/languageService/hoverProvider.js +13 -6
  99. package/dist/languageService/hoverProvider.js.map +1 -1
  100. package/dist/languageService/importAdder.d.ts +5 -1
  101. package/dist/languageService/importAdder.js +50 -14
  102. package/dist/languageService/importAdder.js.map +1 -1
  103. package/dist/languageService/indentationUtils.d.ts +5 -1
  104. package/dist/languageService/indentationUtils.js +12 -2
  105. package/dist/languageService/indentationUtils.js.map +1 -1
  106. package/dist/languageService/insertionPointUtils.js +28 -7
  107. package/dist/languageService/insertionPointUtils.js.map +1 -1
  108. package/dist/languageService/renameModuleProvider.d.ts +20 -10
  109. package/dist/languageService/renameModuleProvider.js +300 -229
  110. package/dist/languageService/renameModuleProvider.js.map +1 -1
  111. package/dist/localization/localize.d.ts +12 -0
  112. package/dist/localization/localize.js +6 -0
  113. package/dist/localization/localize.js.map +1 -1
  114. package/dist/localization/package.nls.en-us.json +8 -1
  115. package/dist/tests/checker.test.js +5 -0
  116. package/dist/tests/checker.test.js.map +1 -1
  117. package/dist/tests/fourslash/hover.docstring.parameter.fourslash.d.ts +1 -0
  118. package/dist/tests/fourslash/hover.docstring.parameter.fourslash.js +57 -0
  119. package/dist/tests/fourslash/hover.docstring.parameter.fourslash.js.map +1 -0
  120. package/dist/tests/fourslash/hover.inferred.fourslash.d.ts +1 -0
  121. package/dist/tests/fourslash/hover.inferred.fourslash.js +24 -0
  122. package/dist/tests/fourslash/hover.inferred.fourslash.js.map +1 -0
  123. package/dist/tests/harness/fourslash/testState.js +9 -2
  124. package/dist/tests/harness/fourslash/testState.js.map +1 -1
  125. package/dist/tests/importAdder.test.js +40 -3
  126. package/dist/tests/importAdder.test.js.map +1 -1
  127. package/dist/tests/indentationUtils.reindent.test.js +1 -1
  128. package/dist/tests/indentationUtils.reindent.test.js.map +1 -1
  129. package/dist/tests/insertionPointUtils.test.js +70 -3
  130. package/dist/tests/insertionPointUtils.test.js.map +1 -1
  131. package/dist/tests/moveSymbol.importAdder.test.js +192 -0
  132. package/dist/tests/moveSymbol.importAdder.test.js.map +1 -0
  133. package/dist/tests/moveSymbol.insertion.test.d.ts +1 -0
  134. package/dist/tests/moveSymbol.insertion.test.js +397 -0
  135. package/dist/tests/moveSymbol.insertion.test.js.map +1 -0
  136. package/dist/tests/moveSymbol.misc.test.d.ts +1 -0
  137. package/dist/tests/moveSymbol.misc.test.js +142 -0
  138. package/dist/tests/moveSymbol.misc.test.js.map +1 -0
  139. package/dist/tests/moveSymbol.updateReference.test.d.ts +1 -0
  140. package/dist/tests/{updateSymbolReference.test.js → moveSymbol.updateReference.test.js} +235 -158
  141. package/dist/tests/moveSymbol.updateReference.test.js.map +1 -0
  142. package/dist/tests/parseTreeUtils.test.js +36 -13
  143. package/dist/tests/parseTreeUtils.test.js.map +1 -1
  144. package/dist/tests/renameModuleTestUtils.js +9 -3
  145. package/dist/tests/renameModuleTestUtils.js.map +1 -1
  146. package/dist/tests/testStateUtils.d.ts +2 -0
  147. package/dist/tests/testStateUtils.js +25 -22
  148. package/dist/tests/testStateUtils.js.map +1 -1
  149. package/dist/tests/textEditUtil.test.d.ts +1 -0
  150. package/dist/tests/textEditUtil.test.js +107 -0
  151. package/dist/tests/textEditUtil.test.js.map +1 -0
  152. package/dist/tests/typeEvaluator1.test.js +4 -0
  153. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  154. package/dist/tests/typeEvaluator2.test.js +12 -0
  155. package/dist/tests/typeEvaluator2.test.js.map +1 -1
  156. package/dist/tests/typeEvaluator3.test.js +9 -0
  157. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  158. package/dist/tests/typeEvaluator4.test.js +5 -1
  159. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  160. package/dist/tests/workspaceEditUtils.test.js +7 -7
  161. package/dist/tests/workspaceEditUtils.test.js.map +1 -1
  162. package/dist/workspaceMap.d.ts +0 -1
  163. package/dist/workspaceMap.js +0 -11
  164. package/dist/workspaceMap.js.map +1 -1
  165. package/package.json +3 -3
  166. package/dist/common/textEditUtils.d.ts +0 -24
  167. package/dist/common/textEditUtils.js +0 -167
  168. package/dist/common/textEditUtils.js.map +0 -1
  169. package/dist/tests/updateSymbolReference.test.js.map +0 -1
  170. /package/dist/tests/{updateSymbolReference.test.d.ts → moveSymbol.importAdder.test.d.ts} +0 -0
@@ -17,11 +17,12 @@ const importStatementUtils_1 = require("../analyzer/importStatementUtils");
17
17
  const parseTreeUtils_1 = require("../analyzer/parseTreeUtils");
18
18
  const parseTreeWalker_1 = require("../analyzer/parseTreeWalker");
19
19
  const sourceMapper_1 = require("../analyzer/sourceMapper");
20
+ const symbolNameUtils_1 = require("../analyzer/symbolNameUtils");
20
21
  const collectionUtils_1 = require("../common/collectionUtils");
21
22
  const debug_1 = require("../common/debug");
22
23
  const pathUtils_1 = require("../common/pathUtils");
23
24
  const positionUtils_1 = require("../common/positionUtils");
24
- const textEditUtils_1 = require("../common/textEditUtils");
25
+ const textEditTracker_1 = require("../common/textEditTracker");
25
26
  const textRange_1 = require("../common/textRange");
26
27
  const parseNodes_1 = require("../parser/parseNodes");
27
28
  const documentSymbolCollector_1 = require("./documentSymbolCollector");
@@ -32,32 +33,22 @@ var UpdateType;
32
33
  UpdateType[UpdateType["Symbol"] = 2] = "Symbol";
33
34
  })(UpdateType || (UpdateType = {}));
34
35
  class RenameModuleProvider {
35
- constructor(_fs, _evaluator, _moduleFilePath, newModuleFilePath, _moduleNameAndType, _newModuleNameAndType, _type, _declarations, _token) {
36
+ constructor(_fs, _evaluator, _moduleFilePath, newModuleFilePath, _moduleNameAndType, _newModuleNameAndType, _type, declarations, _token) {
36
37
  this._fs = _fs;
37
38
  this._evaluator = _evaluator;
38
39
  this._moduleFilePath = _moduleFilePath;
39
40
  this._moduleNameAndType = _moduleNameAndType;
40
41
  this._newModuleNameAndType = _newModuleNameAndType;
41
42
  this._type = _type;
42
- this._declarations = _declarations;
43
+ this.declarations = declarations;
43
44
  this._token = _token;
44
45
  this._aliasIntroduced = new Set();
45
- this._textEditTracker = new textEditUtils_1.TextEditTracker();
46
+ this._textEditTracker = new textEditTracker_1.TextEditTracker();
46
47
  // moduleName and newModuleName are always in the absolute path form.
47
48
  this._newModuleFilePath = (0, pathUtils_1.resolvePaths)(newModuleFilePath);
48
49
  this._moduleNames = this._moduleName.split('.');
49
50
  this._newModuleNames = this._newModuleName.split('.');
50
- if (this._moduleNames.length !== this._newModuleNames.length) {
51
- this._onlyNameChanged = false;
52
- return;
53
- }
54
- let i = 0;
55
- for (i = 0; i < this._moduleNames.length - 1; i++) {
56
- if (this._moduleNames[i] !== this._newModuleNames[i]) {
57
- break;
58
- }
59
- }
60
- this._onlyNameChanged = i === this._moduleNames.length - 1;
51
+ this._onlyNameChanged = (0, importStatementUtils_1.haveSameParentModule)(this._moduleNames, this._newModuleNames);
61
52
  (0, debug_1.assert)(this._type !== UpdateType.Folder || this._onlyNameChanged, 'We only support simple rename for folder');
62
53
  }
63
54
  static createForModule(importResolver, configOptions, evaluator, path, newPath, token) {
@@ -95,6 +86,68 @@ class RenameModuleProvider {
95
86
  }
96
87
  return this._create(importResolver, configOptions, evaluator, path, newPath, UpdateType.Symbol, filteredDecls, token);
97
88
  }
89
+ static canMoveSymbol(evaluator, node) {
90
+ if ((0, symbolNameUtils_1.isPrivateName)(node.value)) {
91
+ return false;
92
+ }
93
+ const lookUpResult = evaluator.lookUpSymbolRecursive(node, node.value, /* honorCodeFlow */ false);
94
+ if (lookUpResult === undefined || lookUpResult.scope.type !== 3 /* Module */) {
95
+ // We only allow moving a symbol at the module level.
96
+ return false;
97
+ }
98
+ // For now, we only supports module level variable, function and class.
99
+ const declarations = lookUpResult.symbol.getDeclarations();
100
+ if (declarations.length === 0) {
101
+ return false;
102
+ }
103
+ return declarations.every((d) => {
104
+ var _a, _b, _c;
105
+ if (!textRange_1.TextRange.containsRange(d.node, node)) {
106
+ return false;
107
+ }
108
+ if ((0, declaration_1.isFunctionDeclaration)(d) || (0, declaration_1.isClassDeclaration)(d)) {
109
+ return true;
110
+ }
111
+ if ((0, declaration_1.isVariableDeclaration)(d)) {
112
+ // We only support simple variable assignment.
113
+ // ex) a = 1
114
+ if (d.typeAliasAnnotation) {
115
+ return false;
116
+ }
117
+ if (d.inferredTypeSource && (0, parseNodes_1.isExpressionNode)(d.inferredTypeSource)) {
118
+ const type = evaluator.getType(d.inferredTypeSource);
119
+ if ((type === null || type === void 0 ? void 0 : type.category) === 10 /* TypeVar */) {
120
+ return false;
121
+ }
122
+ }
123
+ // This make sure we are not one of these
124
+ // ex) a = b = 1
125
+ // a, b = 1, 2
126
+ if (((_a = d.node.parent) === null || _a === void 0 ? void 0 : _a.nodeType) !== 3 /* Assignment */ ||
127
+ ((_c = (_b = d.node.parent) === null || _b === void 0 ? void 0 : _b.parent) === null || _c === void 0 ? void 0 : _c.nodeType) !== 47 /* StatementList */) {
128
+ return false;
129
+ }
130
+ if (d.node.start !== d.node.parent.start) {
131
+ return false;
132
+ }
133
+ return true;
134
+ }
135
+ return false;
136
+ });
137
+ }
138
+ static getSymbolTextRange(parseResults, decl) {
139
+ var _a;
140
+ if ((0, declaration_1.isVariableDeclaration)(decl)) {
141
+ const range = (0, parseTreeUtils_1.getFullStatementRange)(decl.node, parseResults);
142
+ return (_a = (0, positionUtils_1.convertRangeToTextRange)(range, parseResults.tokenizerOutput.lines)) !== null && _a !== void 0 ? _a : decl.node;
143
+ }
144
+ return decl.node;
145
+ }
146
+ static getSymbolFullStatementTextRange(parseResults, decl) {
147
+ var _a;
148
+ const range = (0, parseTreeUtils_1.getFullStatementRange)(decl.node, parseResults, { includeTrailingBlankLines: true });
149
+ return (_a = (0, positionUtils_1.convertRangeToTextRange)(range, parseResults.tokenizerOutput.lines)) !== null && _a !== void 0 ? _a : decl.node;
150
+ }
98
151
  static getRenameModulePath(declarations) {
99
152
  // If we have a decl with no node, we will prefer that decl over others.
100
153
  // The decl with no node is a synthesized alias decl created only for IDE case
@@ -154,21 +207,50 @@ class RenameModuleProvider {
154
207
  }
155
208
  return new RenameModuleProvider(importResolver.fileSystem, evaluator, moduleFilePath, newModuleFilePath, moduleName, newModuleName, type, declarations, token);
156
209
  }
157
- renameReferences(filePath, parseResults) {
210
+ get lastModuleName() {
211
+ return this._moduleNames[this._moduleNames.length - 1];
212
+ }
213
+ get textEditTracker() {
214
+ return this._textEditTracker;
215
+ }
216
+ getEdits() {
217
+ return this._textEditTracker.getEdits(this._token);
218
+ }
219
+ renameReferences(parseResults) {
158
220
  switch (this._type) {
159
221
  case UpdateType.Folder:
160
- return this._renameFolderReferences(filePath, parseResults);
222
+ return this._renameFolderReferences(parseResults);
161
223
  case UpdateType.File:
162
- return this._renameModuleReferences(filePath, parseResults);
224
+ return this._renameModuleReferences(parseResults);
163
225
  case UpdateType.Symbol:
164
- return this._updateSymbolReferences(filePath, parseResults);
226
+ return this._updateSymbolReferences(parseResults);
165
227
  default:
166
228
  return (0, debug_1.assertNever)(this._type, `${this._type} is unknown`);
167
229
  }
168
230
  }
169
- _updateSymbolReferences(filePath, parseResults) {
231
+ tryGetFirstSymbolUsage(parseResults, symbol) {
170
232
  var _a, _b, _c;
171
- const collector = new documentSymbolCollector_1.DocumentSymbolCollector([(0, declarationUtils_1.getNameFromDeclaration)(this._declarations[0]) || ''], this._declarations, this._evaluator, this._token, parseResults.parseTree,
233
+ const name = (_b = (_a = symbol === null || symbol === void 0 ? void 0 : symbol.name) !== null && _a !== void 0 ? _a : (0, declarationUtils_1.getNameFromDeclaration)(this.declarations[0])) !== null && _b !== void 0 ? _b : '';
234
+ const collector = new documentSymbolCollector_1.DocumentSymbolCollector([name], (_c = symbol === null || symbol === void 0 ? void 0 : symbol.decls) !== null && _c !== void 0 ? _c : this.declarations, this._evaluator, this._token, parseResults.parseTree,
235
+ /* treatModuleImportAndFromImportSame */ true,
236
+ /* skipUnreachableCode */ false);
237
+ for (const result of collector.collect().sort((r1, r2) => r1.range.start - r2.range.start)) {
238
+ // We only care about symbol usages, not alias decl of the symbol.
239
+ if ((0, parseTreeUtils_1.isImportModuleName)(result.node) ||
240
+ (0, parseTreeUtils_1.isImportAlias)(result.node) ||
241
+ (0, parseTreeUtils_1.isFromImportModuleName)(result.node) ||
242
+ (0, parseTreeUtils_1.isFromImportName)(result.node) ||
243
+ (0, parseTreeUtils_1.isFromImportAlias)(result.node)) {
244
+ continue;
245
+ }
246
+ return result.range.start;
247
+ }
248
+ return undefined;
249
+ }
250
+ _updateSymbolReferences(parseResults) {
251
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
252
+ const isSource = filePath === this._moduleFilePath;
253
+ const collector = new documentSymbolCollector_1.DocumentSymbolCollector([(0, declarationUtils_1.getNameFromDeclaration)(this.declarations[0]) || ''], this.declarations, this._evaluator, this._token, parseResults.parseTree,
172
254
  /* treatModuleImportAndFromImportSame */ true,
173
255
  /* skipUnreachableCode */ false);
174
256
  // See if we need to insert new import statement
@@ -176,76 +258,73 @@ class RenameModuleProvider {
176
258
  // See whether we have existing import statement for the same module
177
259
  // ex) import [moduleName] or from ... import [moduleName]
178
260
  const imported = importStatements.orderedImports.find((i) => i.moduleName === this._newModuleName);
179
- const nameRemoved = new Set();
261
+ // Indicate whether current file has any usage of the symbol
262
+ let hasSymbolUsage = false;
263
+ const wildcardImports = new Map();
180
264
  const importUsed = new Map();
181
265
  for (const result of collector.collect()) {
182
266
  const nodeFound = result.node;
183
267
  if (nodeFound.nodeType === 49 /* String */) {
184
- // Ignore symbol appearing in the __all__. it should be handled
185
- // when decl is moved.
268
+ if (isSource) {
269
+ // Delete the symbol reference in __all__ if the file is the source file.
270
+ this._textEditTracker.addEditWithTextRange(parseResults, nodeFound, '');
271
+ }
186
272
  continue;
187
273
  }
188
274
  if ((0, parseTreeUtils_1.isFromImportName)(nodeFound)) {
189
- // ex) from ... import [symbol] ...
190
- const fromNode = (_a = nodeFound.parent) === null || _a === void 0 ? void 0 : _a.parent;
191
- const newModuleName = this._getNewModuleName(filePath, fromNode.module.leadingDots > 0,
192
- /* isLastPartImportName */ false);
193
- if (fromNode.imports.length === 1) {
194
- // ex) "from [module] import symbol" to "from [module.changed] import symbol"
195
- this._addResultWithTextRange(filePath, fromNode.module, parseResults, newModuleName);
196
- }
197
- else {
198
- // ex) "from module import symbol, another_symbol" to
199
- // "from module import another_symbol" and "from module.changed import symbol"
200
- // Delete the existing import name including alias.
201
- const importFromAs = nodeFound.parent;
202
- this._addFromImportNameDeletion(filePath, parseResults, nameRemoved, fromNode.imports, importFromAs);
203
- // For now, this won't merge absolute and relative path "from import" statement.
204
- const importNameInfo = {
205
- name: importFromAs.name.value,
206
- alias: (_b = importFromAs.alias) === null || _b === void 0 ? void 0 : _b.value,
207
- };
208
- this._addResultEdits(this._getTextEditsForNewOrExistingFromImport(filePath, fromNode, parseResults, nameRemoved, importStatements, newModuleName, [importNameInfo]));
209
- }
275
+ this._updateNameInFromImportForSymbolReferences(parseResults, importStatements, nodeFound);
210
276
  continue;
211
277
  }
278
+ // Exclude symbol decl itself.
279
+ hasSymbolUsage = isSource
280
+ ? !this.declarations.some((d) => textRange_1.TextRange.containsRange(d.node, nodeFound))
281
+ : true;
212
282
  const dottedName = (0, parseTreeUtils_1.getDottedNameWithGivenNodeAsLastName)(nodeFound);
213
283
  if (dottedName === nodeFound || dottedName.nodeType !== 35 /* MemberAccess */) {
284
+ this._collectWildcardImports(nodeFound, wildcardImports);
214
285
  // ex) from module import foo
215
286
  // foo
216
287
  // foo.method()
217
- //
218
- // from module import *
219
- // foo()
220
- // bar()
221
- //
222
- // we don't need to do anything for wild card case since
223
- // we will preserve __all__ entries.
224
- continue;
225
- }
226
- const moduleName = dottedName.leftExpression.nodeType === 35 /* MemberAccess */
227
- ? dottedName.leftExpression.memberName
228
- : dottedName.leftExpression.nodeType === 38 /* Name */
229
- ? dottedName.leftExpression
230
- : undefined;
231
- if (!moduleName) {
232
- // ex) from module import foo
233
- // getModule().foo
234
288
  continue;
235
289
  }
236
- const moduleDecl = (_c = this._evaluator
237
- .getDeclarationsForNameNode(moduleName)) === null || _c === void 0 ? void 0 : _c.filter((d) => (0, declaration_1.isAliasDeclaration)(d) &&
238
- (d.node.nodeType === 21 /* ImportAs */ || d.node.nodeType === 23 /* ImportFromAs */));
239
- if (!moduleDecl || moduleDecl.length === 0) {
240
- // ex) from xxx import yyy
241
- // yyy.property.foo
242
- continue;
243
- }
244
- const importAs = moduleDecl[0].node;
245
- (0, collectionUtils_1.getOrAdd)(importUsed, importAs, () => []).push(dottedName);
246
- continue;
290
+ this._collectSymbolReferencesPerImports(dottedName, importUsed);
291
+ }
292
+ if (isSource && hasSymbolUsage) {
293
+ // If the original file has references to the symbol moved, we need to either
294
+ // insert import statement or update existing one.
295
+ const newModuleName = (imported === null || imported === void 0 ? void 0 : imported.node.nodeType) === 22 /* ImportFrom */
296
+ ? this._getNewModuleName(filePath, imported.node.module.leadingDots > 0,
297
+ /* isLastPartImportName */ false)
298
+ : undefined;
299
+ const options = (imported === null || imported === void 0 ? void 0 : imported.node.nodeType) === 22 /* ImportFrom */
300
+ ? {
301
+ currentFromImport: imported.node,
302
+ originalModuleName: this._moduleName,
303
+ }
304
+ : undefined;
305
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName, nameForImportFrom: newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), [{ name: (0, declarationUtils_1.getNameFromDeclaration)(this.declarations[0]) }], options);
247
306
  }
307
+ // Handle symbol references that are used off wildcard imports.
308
+ this._processSymbolReferenceOffWildcardImports(parseResults, importStatements, wildcardImports);
248
309
  // Handle symbol references that are used off imported modules.
310
+ this._processSymbolReferenceOffImports(parseResults, importStatements, imported, importUsed);
311
+ }
312
+ _processSymbolReferenceOffImports(parseResults, importStatements, imported, importUsed) {
313
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
314
+ const isDestination = filePath === this._newModuleFilePath;
315
+ if (isDestination) {
316
+ for (const [key, value] of importUsed) {
317
+ if (this._canReplaceImportName(parseResults, key, value)) {
318
+ // We can remove existing import statement.
319
+ this._textEditTracker.deleteImportName(parseResults, key);
320
+ }
321
+ for (const node of value) {
322
+ this._textEditTracker.addEditWithTextRange(parseResults, textRange_1.TextRange.fromBounds(node.start, node.memberName.start), '');
323
+ }
324
+ }
325
+ return;
326
+ }
327
+ // Other files.
249
328
  for (const [key, value] of importUsed) {
250
329
  let referenceModuleName;
251
330
  if (this._canReplaceImportName(parseResults, key, value)) {
@@ -253,25 +332,25 @@ class RenameModuleProvider {
253
332
  if (key.nodeType === 21 /* ImportAs */) {
254
333
  if (moduleName) {
255
334
  referenceModuleName = moduleName;
256
- this._addImportNameDeletion(filePath, parseResults, nameRemoved, key.parent.list, key);
335
+ this._textEditTracker.deleteImportName(parseResults, key);
257
336
  }
258
337
  else {
259
338
  referenceModuleName = key.alias ? key.alias.value : this._newModuleName;
260
- this._addResultWithTextRange(filePath, key.module, parseResults, this._newModuleName);
339
+ this._textEditTracker.addEditWithTextRange(parseResults, key.module, this._newModuleName);
261
340
  }
262
341
  }
263
342
  else {
264
343
  if (moduleName) {
265
344
  referenceModuleName = moduleName;
266
- this._addFromImportNameDeletion(filePath, parseResults, nameRemoved, key.parent.imports, key);
345
+ this._textEditTracker.deleteImportName(parseResults, key);
267
346
  }
268
347
  else {
269
348
  const fromNode = key.parent;
270
349
  const newModuleName = this._getNewModuleName(filePath, fromNode.module.leadingDots > 0,
271
350
  /* isLastPartImportName */ true);
272
351
  referenceModuleName = key.alias ? key.alias.value : this._newLastModuleName;
273
- this._addResultWithTextRange(filePath, fromNode.module, parseResults, newModuleName);
274
- this._addResultWithTextRange(filePath, key.name, parseResults, this._newLastModuleName);
352
+ this._textEditTracker.addEditWithTextRange(parseResults, fromNode.module, newModuleName);
353
+ this._textEditTracker.addEditWithTextRange(parseResults, key.name, this._newLastModuleName);
275
354
  }
276
355
  }
277
356
  }
@@ -282,14 +361,102 @@ class RenameModuleProvider {
282
361
  }
283
362
  else {
284
363
  referenceModuleName = this._newModuleName;
285
- this._addResultEdits((0, importStatementUtils_1.getTextEditsForAutoImportInsertion)([], { name: this._newModuleName }, importStatements, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), parseResults, (0, positionUtils_1.convertOffsetToPosition)(parseResults.parseTree.length, parseResults.tokenizerOutput.lines)).map((e) => ({ filePath, range: e.range, replacementText: e.replacementText })));
364
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType));
286
365
  }
287
366
  }
288
367
  for (const node of value) {
289
- this._addResultWithTextRange(filePath, node.leftExpression, parseResults, referenceModuleName);
368
+ this._textEditTracker.addEditWithTextRange(parseResults, node.leftExpression, referenceModuleName);
290
369
  }
291
370
  }
292
371
  }
372
+ _processSymbolReferenceOffWildcardImports(parseResults, importStatements, wildcardImports) {
373
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
374
+ const isDestination = filePath === this._newModuleFilePath;
375
+ if (isDestination) {
376
+ // Destination file contains the moved symbol decl. no need to insert
377
+ // import statement for the symbol moved.
378
+ return;
379
+ }
380
+ for (const [key, value] of wildcardImports) {
381
+ const fromNode = key;
382
+ const newModuleName = this._getNewModuleName(filePath, fromNode.module.leadingDots > 0,
383
+ /* isLastPartImportName */ false);
384
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName, nameForImportFrom: newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), [...value].map((v) => ({ name: v })), {
385
+ currentFromImport: fromNode,
386
+ originalModuleName: this._moduleName,
387
+ });
388
+ }
389
+ }
390
+ _collectSymbolReferencesPerImports(dottedName, importUsed) {
391
+ var _a;
392
+ const moduleName = dottedName.leftExpression.nodeType === 35 /* MemberAccess */
393
+ ? dottedName.leftExpression.memberName
394
+ : dottedName.leftExpression.nodeType === 38 /* Name */
395
+ ? dottedName.leftExpression
396
+ : undefined;
397
+ if (!moduleName) {
398
+ // ex) from module import foo
399
+ // getModule().foo
400
+ return;
401
+ }
402
+ const moduleDecl = (_a = this._evaluator
403
+ .getDeclarationsForNameNode(moduleName)) === null || _a === void 0 ? void 0 : _a.filter((d) => (0, declaration_1.isAliasDeclaration)(d) &&
404
+ (d.node.nodeType === 21 /* ImportAs */ || d.node.nodeType === 23 /* ImportFromAs */));
405
+ if (!moduleDecl || moduleDecl.length === 0) {
406
+ // ex) from xxx import yyy
407
+ // yyy.property.foo
408
+ return;
409
+ }
410
+ const importAs = moduleDecl[0].node;
411
+ (0, collectionUtils_1.getOrAdd)(importUsed, importAs, () => []).push(dottedName);
412
+ }
413
+ _collectWildcardImports(nodeFound, wildcardImports) {
414
+ const nameDecls = this._evaluator.getDeclarationsForNameNode(nodeFound);
415
+ const aliasDeclFromWildCardImport = nameDecls === null || nameDecls === void 0 ? void 0 : nameDecls.find((d) => d.node.nodeType === 22 /* ImportFrom */ && d.node.isWildcardImport);
416
+ if (!aliasDeclFromWildCardImport || !(0, declaration_1.isAliasDeclaration)(aliasDeclFromWildCardImport)) {
417
+ return;
418
+ }
419
+ // ex) from module import *
420
+ // foo()
421
+ // bar()
422
+ (0, collectionUtils_1.getOrAdd)(wildcardImports, aliasDeclFromWildCardImport.node, () => new Set()).add(nodeFound.value);
423
+ }
424
+ _updateNameInFromImportForSymbolReferences(parseResults, importStatements, nodeFound) {
425
+ var _a;
426
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
427
+ const isDestination = filePath === this._newModuleFilePath;
428
+ // ex) from ... import [symbol] ...
429
+ const importFromAs = nodeFound.parent;
430
+ const fromNode = importFromAs === null || importFromAs === void 0 ? void 0 : importFromAs.parent;
431
+ const newModuleName = this._getNewModuleName(filePath, fromNode.module.leadingDots > 0,
432
+ /* isLastPartImportName */ false);
433
+ if (isDestination) {
434
+ // If we have import statement for the symbol in the destination file,
435
+ // we need to remove it.
436
+ // ex) "from module import symbol, another_symbol" to
437
+ // "from module import another_symbol"
438
+ this._textEditTracker.deleteImportName(parseResults, importFromAs);
439
+ return;
440
+ }
441
+ if (fromNode.imports.length === 1) {
442
+ // ex) "from [module] import symbol" to "from [module.changed] import symbol"
443
+ this._textEditTracker.addEditWithTextRange(parseResults, fromNode.module, newModuleName);
444
+ return;
445
+ }
446
+ // ex) "from module import symbol, another_symbol" to
447
+ // "from module import another_symbol" and "from module.changed import symbol"
448
+ // Delete the existing import name including alias.
449
+ this._textEditTracker.deleteImportName(parseResults, importFromAs);
450
+ // For now, this won't merge absolute and relative path "from import" statement.
451
+ const importNameInfo = {
452
+ name: importFromAs.name.value,
453
+ alias: (_a = importFromAs.alias) === null || _a === void 0 ? void 0 : _a.value,
454
+ };
455
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName, nameForImportFrom: newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), [importNameInfo], {
456
+ currentFromImport: fromNode,
457
+ originalModuleName: this._moduleName,
458
+ });
459
+ }
293
460
  _getReferenceModuleName(importStatements, imported) {
294
461
  var _a, _b;
295
462
  if (imported && imported.node.nodeType === 20 /* Import */) {
@@ -323,34 +490,35 @@ class RenameModuleProvider {
323
490
  // collector will report decls as well. ignore decls.
324
491
  continue;
325
492
  }
493
+ // other symbols from the module are used in the file.
326
494
  if (!symbolReferences.some((s) => textRange_1.TextRange.containsRange(s, result.node))) {
327
495
  return false;
328
496
  }
329
497
  }
330
498
  return true;
331
499
  }
332
- _renameFolderReferences(filePath, parseResults) {
333
- const collector = new documentSymbolCollector_1.DocumentSymbolCollector([this.lastModuleName], this._declarations, this._evaluator, this._token, parseResults.parseTree,
500
+ _renameFolderReferences(parseResults) {
501
+ const collector = new documentSymbolCollector_1.DocumentSymbolCollector([this.lastModuleName], this.declarations, this._evaluator, this._token, parseResults.parseTree,
334
502
  /* treatModuleImportAndFromImportSame */ true,
335
503
  /* skipUnreachableCode */ false);
336
504
  // We only support simple rename of folder. Change all occurrence of the old folder name
337
505
  // to new name.
338
506
  for (const result of collector.collect()) {
339
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
507
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
340
508
  }
341
509
  }
342
- _renameModuleReferences(filePath, parseResults) {
343
- const collector = new documentSymbolCollector_1.DocumentSymbolCollector([this.lastModuleName], this._declarations, this._evaluator, this._token, parseResults.parseTree,
510
+ _renameModuleReferences(parseResults) {
511
+ const collector = new documentSymbolCollector_1.DocumentSymbolCollector([this.lastModuleName], this.declarations, this._evaluator, this._token, parseResults.parseTree,
344
512
  /* treatModuleImportAndFromImportSame */ true,
345
513
  /* skipUnreachableCode */ false);
346
- const nameRemoved = new Set();
347
514
  const results = collector.collect();
348
515
  // Update module references first.
349
- this._updateModuleReferences(filePath, parseResults, nameRemoved, results);
516
+ this._updateModuleReferences(parseResults, results);
350
517
  // If the module file has moved, we need to update all relative paths used in the file to reflect the move.
351
- this._updateRelativeModuleNamePath(filePath, parseResults, nameRemoved, results);
518
+ this._updateRelativeModuleNamePath(parseResults, results);
352
519
  }
353
- _updateRelativeModuleNamePath(filePath, parseResults, nameRemoved, results) {
520
+ _updateRelativeModuleNamePath(parseResults, results) {
521
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
354
522
  if (filePath !== this._moduleFilePath) {
355
523
  // We only update relative import paths for the file that has moved.
356
524
  return;
@@ -358,7 +526,7 @@ class RenameModuleProvider {
358
526
  let importStatements;
359
527
  // Filter out module name that is already re-written.
360
528
  for (const edit of this._getNewRelativeModuleNamesForFileMoved(filePath, ModuleNameCollector.collect(parseResults.parseTree).filter((m) => !results.some((r) => textRange_1.TextRange.containsRange(m.parent, r.node))))) {
361
- this._addResultWithTextRange(filePath, edit.moduleName, parseResults, edit.newModuleName);
529
+ this._textEditTracker.addEditWithTextRange(parseResults, edit.moduleName, edit.newModuleName);
362
530
  if (!edit.itemsToMove) {
363
531
  continue;
364
532
  }
@@ -370,28 +538,35 @@ class RenameModuleProvider {
370
538
  const fromNode = edit.moduleName.parent;
371
539
  // First, delete existing exported symbols from "from import" statement.
372
540
  for (const importFromAs of edit.itemsToMove) {
373
- this._addFromImportNameDeletion(filePath, parseResults, nameRemoved, fromNode.imports, importFromAs);
541
+ this._textEditTracker.deleteImportName(parseResults, importFromAs);
374
542
  }
375
543
  importStatements =
376
544
  importStatements !== null && importStatements !== void 0 ? importStatements : (0, importStatementUtils_1.getTopLevelImports)(parseResults.parseTree, /* includeImplicitImports */ false);
377
545
  // For now, this won't merge absolute and relative path "from import"
378
546
  // statement.
379
- this._addResultEdits(this._getTextEditsForNewOrExistingFromImport(filePath, fromNode, parseResults, nameRemoved, importStatements, (0, importStatementUtils_1.getRelativeModuleName)(this._fs, this._newModuleFilePath, this._newModuleFilePath,
380
- /* ignoreFolderStructure */ false,
381
- /* sourceIsFile */ true), edit.itemsToMove.map((i) => {
547
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, {
548
+ name: this._newModuleName,
549
+ nameForImportFrom: (0, importStatementUtils_1.getRelativeModuleName)(this._fs, this._newModuleFilePath, this._newModuleFilePath,
550
+ /* ignoreFolderStructure */ false,
551
+ /* sourceIsFile */ true),
552
+ }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), edit.itemsToMove.map((i) => {
382
553
  var _a;
383
554
  return { name: i.name.value, alias: (_a = i.alias) === null || _a === void 0 ? void 0 : _a.value };
384
- })));
555
+ }), {
556
+ currentFromImport: fromNode,
557
+ originalModuleName: this._moduleName,
558
+ });
385
559
  }
386
560
  }
387
- _updateModuleReferences(filePath, parseResults, nameRemoved, results) {
561
+ _updateModuleReferences(parseResults, results) {
388
562
  var _a, _b, _c, _d, _e;
563
+ const filePath = (0, analyzerNodeInfo_1.getFileInfo)(parseResults.parseTree).filePath;
389
564
  let importStatements;
390
565
  for (const result of results) {
391
566
  const nodeFound = result.node;
392
567
  if (nodeFound.nodeType === 49 /* String */) {
393
568
  // ex) __all__ = ["[a]"]
394
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
569
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
395
570
  continue;
396
571
  }
397
572
  if ((0, parseTreeUtils_1.isImportModuleName)(nodeFound)) {
@@ -419,17 +594,17 @@ class RenameModuleProvider {
419
594
  !moduleNameNode.parent.alias &&
420
595
  this._newModuleNames.length > 1) {
421
596
  this._aliasIntroduced.add(moduleNameNode.parent);
422
- this._addResultWithTextRange(filePath, moduleNameNode, parseResults, `${this._newModuleName} as ${this._newLastModuleName}`);
597
+ this._textEditTracker.addEditWithTextRange(parseResults, moduleNameNode, `${this._newModuleName} as ${this._newLastModuleName}`);
423
598
  continue;
424
599
  }
425
600
  // Otherwise, update whole module name to new name
426
601
  // ex) import [xxx.yyy] to import [aaa.bbb]
427
- this._addResultWithTextRange(filePath, moduleNameNode, parseResults, this._newModuleName);
602
+ this._textEditTracker.addEditWithTextRange(parseResults, moduleNameNode, this._newModuleName);
428
603
  continue;
429
604
  }
430
605
  if ((0, parseTreeUtils_1.isImportAlias)(nodeFound)) {
431
606
  // ex) import xxx as [yyy] to import xxx as [zzz]
432
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
607
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
433
608
  continue;
434
609
  }
435
610
  if ((0, parseTreeUtils_1.isFromImportModuleName)(nodeFound)) {
@@ -456,7 +631,7 @@ class RenameModuleProvider {
456
631
  // We don't have any sub modules, we can change module name to new one.
457
632
  // Update whole module name to new name.
458
633
  // ex) from [xxx.yyy] import zzz to from [aaa.bbb] import zzz
459
- this._addResultWithTextRange(filePath, moduleNameNode, parseResults, this._getNewModuleName(filePath, moduleNameNode.leadingDots > 0,
634
+ this._textEditTracker.addEditWithTextRange(parseResults, moduleNameNode, this._getNewModuleName(filePath, moduleNameNode.leadingDots > 0,
460
635
  /* isLastPartImportName */ false));
461
636
  continue;
462
637
  }
@@ -470,31 +645,32 @@ class RenameModuleProvider {
470
645
  // Update module name if needed.
471
646
  if (fromNode.module.leadingDots > 0) {
472
647
  for (const edit of this._getNewRelativeModuleNamesForFileMoved(filePath, [fromNode.module])) {
473
- this._addResultWithTextRange(filePath, edit.moduleName, parseResults, edit.newModuleName);
648
+ this._textEditTracker.addEditWithTextRange(parseResults, edit.moduleName, edit.newModuleName);
474
649
  }
475
650
  }
476
651
  // First, delete existing exported symbols from "from import" statement.
477
652
  for (const importFromAs of exportedSymbols) {
478
- this._addFromImportNameDeletion(filePath, parseResults, nameRemoved, fromNode.imports, importFromAs);
653
+ this._textEditTracker.deleteImportName(parseResults, importFromAs);
479
654
  }
480
655
  importStatements =
481
656
  importStatements !== null && importStatements !== void 0 ? importStatements : (0, importStatementUtils_1.getTopLevelImports)(parseResults.parseTree, /* includeImplicitImports */ false);
482
657
  // For now, this won't merge absolute and relative path "from import"
483
658
  // statement.
484
- this._addResultEdits(this._getTextEditsForNewOrExistingFromImport(filePath, fromNode, parseResults, nameRemoved, importStatements, this._newModuleName, exportedSymbols.map((i) => {
659
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), exportedSymbols.map((i) => {
485
660
  var _a;
486
- const name = results.findIndex((r) => r.node === i.name) >= 0
487
- ? this._newLastModuleName
488
- : i.name.value;
661
+ const name = results.findIndex((r) => r.node === i.name) >= 0 ? this._newLastModuleName : i.name.value;
489
662
  const alias = results.findIndex((r) => r.node === i.alias) >= 0
490
663
  ? this._newLastModuleName
491
664
  : (_a = i.alias) === null || _a === void 0 ? void 0 : _a.value;
492
665
  return { name, alias };
493
- })));
666
+ }), {
667
+ currentFromImport: fromNode,
668
+ originalModuleName: this._moduleName,
669
+ });
494
670
  continue;
495
671
  }
496
672
  if ((0, parseTreeUtils_1.isFromImportName)(nodeFound)) {
497
- if (nameRemoved.has(nodeFound.id)) {
673
+ if (this._textEditTracker.isNodeRemoved(nodeFound)) {
498
674
  // Import name is already removed.
499
675
  continue;
500
676
  }
@@ -505,13 +681,13 @@ class RenameModuleProvider {
505
681
  // Existing logic should make sure re-exported symbol name work as before after
506
682
  // symbol rename.
507
683
  if (this._isExportedSymbol(nodeFound)) {
508
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
684
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
509
685
  continue;
510
686
  }
511
687
  if (fromNode.imports.length === 1) {
512
688
  // ex) from xxx import [yyy] to from [aaa.bbb] import [zzz]
513
- this._addResultWithTextRange(filePath, fromNode.module, parseResults, newModuleName);
514
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
689
+ this._textEditTracker.addEditWithTextRange(parseResults, fromNode.module, newModuleName);
690
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
515
691
  }
516
692
  else {
517
693
  // Delete the existing import name including alias.
@@ -519,10 +695,10 @@ class RenameModuleProvider {
519
695
  // Update module name if needed.
520
696
  if (fromNode.module.leadingDots > 0) {
521
697
  for (const edit of this._getNewRelativeModuleNamesForFileMoved(filePath, [fromNode.module])) {
522
- this._addResultWithTextRange(filePath, edit.moduleName, parseResults, edit.newModuleName);
698
+ this._textEditTracker.addEditWithTextRange(parseResults, edit.moduleName, edit.newModuleName);
523
699
  }
524
700
  }
525
- this._addFromImportNameDeletion(filePath, parseResults, nameRemoved, fromNode.imports, importFromAs);
701
+ this._textEditTracker.deleteImportName(parseResults, importFromAs);
526
702
  importStatements =
527
703
  importStatements !== null && importStatements !== void 0 ? importStatements : (0, importStatementUtils_1.getTopLevelImports)(parseResults.parseTree, /* includeImplicitImports */ false);
528
704
  // ex) from xxx import yyy, [zzz] to
@@ -541,17 +717,20 @@ class RenameModuleProvider {
541
717
  ? this._newLastModuleName
542
718
  : (_d = importFromAs.alias) === null || _d === void 0 ? void 0 : _d.value,
543
719
  };
544
- this._addResultEdits(this._getTextEditsForNewOrExistingFromImport(filePath, fromNode, parseResults, nameRemoved, importStatements, newModuleName, [importNameInfo]));
720
+ this._textEditTracker.addOrUpdateImport(parseResults, importStatements, { name: this._newModuleName, nameForImportFrom: newModuleName }, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), [importNameInfo], {
721
+ currentFromImport: fromNode,
722
+ originalModuleName: this._moduleName,
723
+ });
545
724
  }
546
725
  continue;
547
726
  }
548
727
  if ((0, parseTreeUtils_1.isFromImportAlias)(nodeFound)) {
549
- if (nameRemoved.has(nodeFound.id)) {
728
+ if (this._textEditTracker.isNodeRemoved(nodeFound)) {
550
729
  // alias is already removed.
551
730
  continue;
552
731
  }
553
732
  // ex) from ccc import xxx as [yyy] to from ccc import xxx as [zzz]
554
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
733
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
555
734
  continue;
556
735
  }
557
736
  /** TODO: if we get more than 1 decls, flag it as attention needed */
@@ -561,7 +740,7 @@ class RenameModuleProvider {
561
740
  // Simple case. only name has changed. but not path.
562
741
  // Just replace name to new symbol name.
563
742
  // ex) a.[b].foo() to a.[z].foo()
564
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
743
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
565
744
  continue;
566
745
  }
567
746
  if (decls === null || decls === void 0 ? void 0 : decls.some((d) => !d.usesLocalName &&
@@ -570,7 +749,7 @@ class RenameModuleProvider {
570
749
  const dottedName = (0, parseTreeUtils_1.getDottedNameWithGivenNodeAsLastName)(nodeFound);
571
750
  if (((_e = dottedName.parent) === null || _e === void 0 ? void 0 : _e.nodeType) !== 35 /* MemberAccess */) {
572
751
  // Replace whole dotted name with new module name.
573
- this._addResultWithTextRange(filePath, dottedName, parseResults, this._newModuleName);
752
+ this._textEditTracker.addEditWithTextRange(parseResults, dottedName, this._newModuleName);
574
753
  continue;
575
754
  }
576
755
  // Check whether name after me is sub module or not.
@@ -586,11 +765,11 @@ class RenameModuleProvider {
586
765
  // Next name is actual symbol. Replace whole name to new module name.
587
766
  // ex) import a.b.c
588
767
  // [a.b.c].[foo]()
589
- this._addResultWithTextRange(filePath, dottedName, parseResults, this._newModuleName);
768
+ this._textEditTracker.addEditWithTextRange(parseResults, dottedName, this._newModuleName);
590
769
  continue;
591
770
  }
592
771
  if (result.node.value !== this._newLastModuleName) {
593
- this._addResultWithTextRange(filePath, result.range, parseResults, this._newLastModuleName);
772
+ this._textEditTracker.addEditWithTextRange(parseResults, result.range, this._newLastModuleName);
594
773
  continue;
595
774
  }
596
775
  }
@@ -705,12 +884,6 @@ class RenameModuleProvider {
705
884
  // ex) x.y.z used in "from x.y.z import ..."
706
885
  return moduleName;
707
886
  }
708
- getEdits() {
709
- return this._textEditTracker.getEdits(this._token);
710
- }
711
- get lastModuleName() {
712
- return this._moduleNames[this._moduleNames.length - 1];
713
- }
714
887
  get _moduleName() {
715
888
  return this._moduleNameAndType.moduleName;
716
889
  }
@@ -720,108 +893,6 @@ class RenameModuleProvider {
720
893
  get _newModuleName() {
721
894
  return this._newModuleNameAndType.moduleName;
722
895
  }
723
- _addImportNameDeletion(filePath, parseResults, nameRemoved, imports, importToDelete) {
724
- this._addImportNameDeletionInternal(filePath, parseResults, nameRemoved, imports, importToDelete, 20 /* Import */);
725
- // Mark that we don't need to process these node again later.
726
- nameRemoved.add(importToDelete.module.id);
727
- importToDelete.module.nameParts.forEach((n) => nameRemoved.add(n.id));
728
- if (importToDelete.alias) {
729
- nameRemoved.add(importToDelete.alias.id);
730
- }
731
- }
732
- _addFromImportNameDeletion(filePath, parseResults, nameRemoved, imports, importToDelete) {
733
- this._addImportNameDeletionInternal(filePath, parseResults, nameRemoved, imports, importToDelete, 22 /* ImportFrom */);
734
- // Mark that we don't need to process these node again later.
735
- nameRemoved.add(importToDelete.name.id);
736
- if (importToDelete.alias) {
737
- nameRemoved.add(importToDelete.alias.id);
738
- }
739
- }
740
- _addImportNameDeletionInternal(filePath, parseResults, nameRemoved, imports, importToDelete, importKind) {
741
- const ranges = (0, importStatementUtils_1.getTextRangeForImportNameDeletion)(imports, imports.findIndex((v) => v === importToDelete));
742
- ranges.forEach((r) => this._addResultWithTextRange(filePath, r, parseResults, ''));
743
- // Mark that we don't need to process these node again later.
744
- nameRemoved.add(importToDelete.id);
745
- // Check whether we have deleted all trailing import names.
746
- // If either no trailing import is deleted or handled properly
747
- // then, there is nothing to do. otherwise, either delete the whole statement
748
- // or remove trailing comma.
749
- // ex) from x import [y], z or from x import y[, z]
750
- let lastImportIndexNotDeleted = 0;
751
- for (lastImportIndexNotDeleted = imports.length - 1; lastImportIndexNotDeleted >= 0; lastImportIndexNotDeleted--) {
752
- if (!nameRemoved.has(imports[lastImportIndexNotDeleted].id)) {
753
- break;
754
- }
755
- }
756
- if (lastImportIndexNotDeleted === -1) {
757
- // Whole statement is deleted. Remove the statement itself.
758
- // ex) [from x import a, b, c] or [import a]
759
- const importStatement = (0, parseTreeUtils_1.getFirstAncestorOrSelfOfKind)(importToDelete, importKind);
760
- if (importStatement) {
761
- this._textEditTracker.addEdit(filePath, (0, parseTreeUtils_1.getFullStatementRange)(importStatement, parseResults.tokenizerOutput), '');
762
- }
763
- }
764
- else if (lastImportIndexNotDeleted >= 0 && lastImportIndexNotDeleted < imports.length - 2) {
765
- // We need to delete trailing comma
766
- // ex) from x import a, [b, c]
767
- const start = textRange_1.TextRange.getEnd(imports[lastImportIndexNotDeleted]);
768
- const length = textRange_1.TextRange.getEnd(imports[lastImportIndexNotDeleted + 1]) - start;
769
- this._addResultWithTextRange(filePath, { start, length }, parseResults, '');
770
- }
771
- }
772
- _addResultWithTextRange(filePath, range, parseResults, newName) {
773
- const existing = parseResults.text.substr(range.start, range.length);
774
- if (existing === newName) {
775
- // No change. Return as it is.
776
- return;
777
- }
778
- this._textEditTracker.addEdit(filePath, (0, positionUtils_1.convertTextRangeToRange)(range, parseResults.tokenizerOutput.lines), newName);
779
- }
780
- _addResultEdits(edits) {
781
- this._textEditTracker.addEdits(...edits);
782
- }
783
- _getTextEditsForNewOrExistingFromImport(filePath, currentFromImport, parseResults, nameRemoved, importStatements, moduleName, importNameInfo) {
784
- // See whether we have existing from import statement for the same module
785
- // ex) from [|moduleName|] import subModule
786
- const imported = importStatements.orderedImports.find((i) => i.moduleName === moduleName);
787
- if (imported && imported.node.nodeType === 22 /* ImportFrom */ && !imported.node.isWildcardImport) {
788
- const edits = (0, importStatementUtils_1.getTextEditsForAutoImportSymbolAddition)(importNameInfo, imported, parseResults);
789
- if (imported.node !== currentFromImport) {
790
- // Add what we want to the existing "import from" statement as long as it is not the same import
791
- // node we are working on.
792
- return edits.map((e) => ({ filePath, range: e.range, replacementText: e.replacementText }));
793
- }
794
- // Check whether we can avoid creating a new statement. We can't just merge with existing one since
795
- // we could create invalid text edits (2 edits that change the same span, or invalid replacement text since
796
- // texts on the node has changed)
797
- if (this._onlyNameChanged && importNameInfo.length === 1 && edits.length === 1) {
798
- const deletions = this._textEditTracker.getDeletionsForSpan(filePath, edits[0].range);
799
- if (deletions.length === 0) {
800
- return [{ filePath, range: edits[0].range, replacementText: edits[0].replacementText }];
801
- }
802
- else {
803
- const alias = importNameInfo[0].alias === this._newLastModuleName
804
- ? this.lastModuleName
805
- : importNameInfo[0].alias;
806
- const importName = currentFromImport.imports.find((i) => { var _a; return i.name.value === this.lastModuleName && ((_a = i.alias) === null || _a === void 0 ? void 0 : _a.value) === alias; });
807
- if (importName) {
808
- this._textEditTracker.removeEdits(filePath, deletions);
809
- if (importName.alias) {
810
- nameRemoved.delete(importName.alias.id);
811
- }
812
- return [
813
- {
814
- filePath,
815
- range: (0, positionUtils_1.convertTextRangeToRange)(importName.name, parseResults.tokenizerOutput.lines),
816
- replacementText: this._newLastModuleName,
817
- },
818
- ];
819
- }
820
- }
821
- }
822
- }
823
- return (0, importStatementUtils_1.getTextEditsForAutoImportInsertion)(importNameInfo, { name: moduleName }, importStatements, (0, importStatementUtils_1.getImportGroupFromModuleNameAndType)(this._newModuleNameAndType), parseResults, (0, positionUtils_1.convertOffsetToPosition)(parseResults.parseTree.length, parseResults.tokenizerOutput.lines)).map((e) => ({ filePath, range: e.range, replacementText: e.replacementText }));
824
- }
825
896
  }
826
897
  exports.RenameModuleProvider = RenameModuleProvider;
827
898
  class ModuleNameCollector extends parseTreeWalker_1.ParseTreeWalker {