@zzzen/pyright-internal 1.2.0-dev.20230430 → 1.2.0-dev.20230507

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 (160) hide show
  1. package/dist/analyzer/backgroundAnalysisProgram.d.ts +3 -0
  2. package/dist/analyzer/backgroundAnalysisProgram.js +12 -0
  3. package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
  4. package/dist/analyzer/checker.d.ts +1 -0
  5. package/dist/analyzer/checker.js +52 -4
  6. package/dist/analyzer/checker.js.map +1 -1
  7. package/dist/analyzer/constructors.d.ts +6 -0
  8. package/dist/analyzer/constructors.js +456 -0
  9. package/dist/analyzer/constructors.js.map +1 -0
  10. package/dist/analyzer/dataClasses.js +84 -0
  11. package/dist/analyzer/dataClasses.js.map +1 -1
  12. package/dist/analyzer/enums.js +54 -8
  13. package/dist/analyzer/enums.js.map +1 -1
  14. package/dist/analyzer/importStatementUtils.d.ts +2 -2
  15. package/dist/analyzer/importStatementUtils.js.map +1 -1
  16. package/dist/analyzer/namedTuples.js +1 -1
  17. package/dist/analyzer/namedTuples.js.map +1 -1
  18. package/dist/analyzer/operations.d.ts +16 -0
  19. package/dist/analyzer/operations.js +749 -0
  20. package/dist/analyzer/operations.js.map +1 -0
  21. package/dist/analyzer/parseTreeUtils.d.ts +4 -2
  22. package/dist/analyzer/parseTreeUtils.js +32 -1
  23. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  24. package/dist/analyzer/patternMatching.js +16 -0
  25. package/dist/analyzer/patternMatching.js.map +1 -1
  26. package/dist/analyzer/program.d.ts +5 -17
  27. package/dist/analyzer/program.js +46 -493
  28. package/dist/analyzer/program.js.map +1 -1
  29. package/dist/analyzer/service.d.ts +3 -11
  30. package/dist/analyzer/service.js +16 -12
  31. package/dist/analyzer/service.js.map +1 -1
  32. package/dist/analyzer/sourceFile.d.ts +10 -33
  33. package/dist/analyzer/sourceFile.js +225 -181
  34. package/dist/analyzer/sourceFile.js.map +1 -1
  35. package/dist/analyzer/sourceFileInfoUtils.d.ts +3 -9
  36. package/dist/analyzer/sourceFileInfoUtils.js.map +1 -1
  37. package/dist/analyzer/typeEvaluator.js +100 -1285
  38. package/dist/analyzer/typeEvaluator.js.map +1 -1
  39. package/dist/analyzer/typeEvaluatorTypes.d.ts +38 -7
  40. package/dist/analyzer/typeEvaluatorTypes.js +33 -1
  41. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  42. package/dist/analyzer/typeGuards.js +2 -8
  43. package/dist/analyzer/typeGuards.js.map +1 -1
  44. package/dist/analyzer/typeUtils.d.ts +2 -0
  45. package/dist/analyzer/typeUtils.js +33 -3
  46. package/dist/analyzer/typeUtils.js.map +1 -1
  47. package/dist/analyzer/typeVarContext.d.ts +5 -5
  48. package/dist/analyzer/typeVarContext.js +7 -0
  49. package/dist/analyzer/typeVarContext.js.map +1 -1
  50. package/dist/analyzer/typedDicts.js +2 -2
  51. package/dist/analyzer/typedDicts.js.map +1 -1
  52. package/dist/analyzer/types.d.ts +4 -2
  53. package/dist/analyzer/types.js +7 -0
  54. package/dist/analyzer/types.js.map +1 -1
  55. package/dist/common/extensibility.d.ts +2 -1
  56. package/dist/common/extensibility.js.map +1 -1
  57. package/dist/common/pathUtils.d.ts +11 -11
  58. package/dist/common/pathUtils.js.map +1 -1
  59. package/dist/common/workspaceEditUtils.d.ts +5 -5
  60. package/dist/common/workspaceEditUtils.js.map +1 -1
  61. package/dist/languageServerBase.d.ts +1 -2
  62. package/dist/languageServerBase.js +8 -13
  63. package/dist/languageServerBase.js.map +1 -1
  64. package/dist/languageService/callHierarchyProvider.d.ts +1 -1
  65. package/dist/languageService/callHierarchyProvider.js +5 -5
  66. package/dist/languageService/callHierarchyProvider.js.map +1 -1
  67. package/dist/languageService/completionProvider.d.ts +10 -13
  68. package/dist/languageService/completionProvider.js +21 -10
  69. package/dist/languageService/completionProvider.js.map +1 -1
  70. package/dist/languageService/documentHighlightProvider.js +1 -1
  71. package/dist/languageService/documentHighlightProvider.js.map +1 -1
  72. package/dist/languageService/documentSymbolCollector.d.ts +6 -7
  73. package/dist/languageService/documentSymbolCollector.js +17 -8
  74. package/dist/languageService/documentSymbolCollector.js.map +1 -1
  75. package/dist/languageService/hoverProvider.d.ts +4 -3
  76. package/dist/languageService/hoverProvider.js +29 -35
  77. package/dist/languageService/hoverProvider.js.map +1 -1
  78. package/dist/languageService/referencesProvider.d.ts +7 -12
  79. package/dist/languageService/referencesProvider.js +25 -17
  80. package/dist/languageService/referencesProvider.js.map +1 -1
  81. package/dist/languageService/renameProvider.d.ts +17 -0
  82. package/dist/languageService/renameProvider.js +143 -0
  83. package/dist/languageService/renameProvider.js.map +1 -0
  84. package/dist/localization/localize.d.ts +17 -14
  85. package/dist/localization/localize.js +4 -6
  86. package/dist/localization/localize.js.map +1 -1
  87. package/dist/localization/package.nls.en-us.json +5 -6
  88. package/dist/tests/documentSymbolCollector.test.js +3 -3
  89. package/dist/tests/documentSymbolCollector.test.js.map +1 -1
  90. package/dist/tests/fourslash/fourslash.d.ts +4 -4
  91. package/dist/tests/fourslash/missingTypeStub.codeAction.fourslash.js +1 -1
  92. package/dist/tests/fourslash/missingTypeStub.codeAction.fourslash.js.map +1 -1
  93. package/dist/tests/harness/fourslash/testState.d.ts +3 -3
  94. package/dist/tests/harness/fourslash/testState.js +14 -14
  95. package/dist/tests/harness/fourslash/testState.js.map +1 -1
  96. package/dist/tests/sourceFile.test.js +1 -1
  97. package/dist/tests/sourceFile.test.js.map +1 -1
  98. package/dist/tests/testStateUtils.d.ts +2 -2
  99. package/dist/tests/testStateUtils.js +38 -8
  100. package/dist/tests/testStateUtils.js.map +1 -1
  101. package/dist/tests/typeEvaluator2.test.js +1 -1
  102. package/dist/tests/typeEvaluator3.test.js +1 -1
  103. package/dist/tests/typeEvaluator4.test.js +9 -1
  104. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  105. package/dist/tests/typeEvaluator5.test.js +4 -0
  106. package/dist/tests/typeEvaluator5.test.js.map +1 -1
  107. package/dist/tests/workspaceEditUtils.test.js +84 -0
  108. package/dist/tests/workspaceEditUtils.test.js.map +1 -1
  109. package/package.json +4 -4
  110. package/dist/languageService/indentationUtils.d.ts +0 -16
  111. package/dist/languageService/indentationUtils.js +0 -727
  112. package/dist/languageService/indentationUtils.js.map +0 -1
  113. package/dist/languageService/insertionPointUtils.d.ts +0 -9
  114. package/dist/languageService/insertionPointUtils.js +0 -132
  115. package/dist/languageService/insertionPointUtils.js.map +0 -1
  116. package/dist/languageService/renameModuleProvider.d.ts +0 -65
  117. package/dist/languageService/renameModuleProvider.js +0 -939
  118. package/dist/languageService/renameModuleProvider.js.map +0 -1
  119. package/dist/tests/indentationUtils.ptvs.test.d.ts +0 -1
  120. package/dist/tests/indentationUtils.ptvs.test.js +0 -324
  121. package/dist/tests/indentationUtils.ptvs.test.js.map +0 -1
  122. package/dist/tests/indentationUtils.reindent.test.d.ts +0 -1
  123. package/dist/tests/indentationUtils.reindent.test.js +0 -372
  124. package/dist/tests/indentationUtils.reindent.test.js.map +0 -1
  125. package/dist/tests/indentationUtils.test.d.ts +0 -1
  126. package/dist/tests/indentationUtils.test.js +0 -502
  127. package/dist/tests/indentationUtils.test.js.map +0 -1
  128. package/dist/tests/insertionPointUtils.test.d.ts +0 -1
  129. package/dist/tests/insertionPointUtils.test.js +0 -154
  130. package/dist/tests/insertionPointUtils.test.js.map +0 -1
  131. package/dist/tests/moveSymbol.importAdder.test.d.ts +0 -1
  132. package/dist/tests/moveSymbol.importAdder.test.js +0 -298
  133. package/dist/tests/moveSymbol.importAdder.test.js.map +0 -1
  134. package/dist/tests/moveSymbol.insertion.test.d.ts +0 -1
  135. package/dist/tests/moveSymbol.insertion.test.js +0 -537
  136. package/dist/tests/moveSymbol.insertion.test.js.map +0 -1
  137. package/dist/tests/moveSymbol.misc.test.d.ts +0 -1
  138. package/dist/tests/moveSymbol.misc.test.js +0 -169
  139. package/dist/tests/moveSymbol.misc.test.js.map +0 -1
  140. package/dist/tests/moveSymbol.updateReference.test.d.ts +0 -1
  141. package/dist/tests/moveSymbol.updateReference.test.js +0 -1071
  142. package/dist/tests/moveSymbol.updateReference.test.js.map +0 -1
  143. package/dist/tests/renameModule.folder.test.d.ts +0 -1
  144. package/dist/tests/renameModule.folder.test.js +0 -229
  145. package/dist/tests/renameModule.folder.test.js.map +0 -1
  146. package/dist/tests/renameModule.fromImports.test.d.ts +0 -1
  147. package/dist/tests/renameModule.fromImports.test.js +0 -790
  148. package/dist/tests/renameModule.fromImports.test.js.map +0 -1
  149. package/dist/tests/renameModule.imports.test.d.ts +0 -1
  150. package/dist/tests/renameModule.imports.test.js +0 -380
  151. package/dist/tests/renameModule.imports.test.js.map +0 -1
  152. package/dist/tests/renameModule.misc.test.d.ts +0 -1
  153. package/dist/tests/renameModule.misc.test.js +0 -615
  154. package/dist/tests/renameModule.misc.test.js.map +0 -1
  155. package/dist/tests/renameModule.relativePath.test.d.ts +0 -1
  156. package/dist/tests/renameModule.relativePath.test.js +0 -231
  157. package/dist/tests/renameModule.relativePath.test.js.map +0 -1
  158. package/dist/tests/renameModuleTestUtils.d.ts +0 -4
  159. package/dist/tests/renameModuleTestUtils.js +0 -76
  160. package/dist/tests/renameModuleTestUtils.js.map +0 -1
@@ -72,50 +72,58 @@ var IPythonMode;
72
72
  // Each cell is its own document.
73
73
  IPythonMode[IPythonMode["CellDocs"] = 1] = "CellDocs";
74
74
  })(IPythonMode = exports.IPythonMode || (exports.IPythonMode = {}));
75
- class SourceFile {
76
- constructor(fs, filePath, moduleName, isThirdPartyImport, isThirdPartyPyTypedPresent, console, logTracker, realFilePath, ipythonMode = IPythonMode.None) {
77
- // True if the file appears to have been deleted.
78
- this._isFileDeleted = false;
75
+ class WriteableData {
76
+ constructor() {
79
77
  // Number that is incremented every time the diagnostics
80
78
  // are updated.
81
- this._diagnosticVersion = 0;
79
+ this.diagnosticVersion = 0;
82
80
  // Generation count of the file contents. When the contents
83
81
  // change, this is incremented.
84
- this._fileContentsVersion = 0;
82
+ this.fileContentsVersion = 0;
85
83
  // Length and hash of the file the last time it was read from disk.
86
- this._lastFileContentLength = undefined;
87
- this._lastFileContentHash = undefined;
84
+ this.lastFileContentLength = undefined;
85
+ this.lastFileContentHash = undefined;
88
86
  // Version of file contents that have been analyzed.
89
- this._analyzedFileContentsVersion = -1;
87
+ this.analyzedFileContentsVersion = -1;
90
88
  // Do we need to walk the parse tree and clean
91
89
  // the binder information hanging from it?
92
- this._parseTreeNeedsCleaning = false;
90
+ this.parseTreeNeedsCleaning = false;
93
91
  // Reentrancy check for binding.
94
- this._isBindingInProgress = false;
92
+ this.isBindingInProgress = false;
95
93
  // Diagnostics generated during different phases of analysis.
96
- this._parseDiagnostics = [];
97
- this._commentDiagnostics = [];
98
- this._bindDiagnostics = [];
99
- this._checkerDiagnostics = [];
100
- this._typeIgnoreLines = new Map();
101
- this._pyrightIgnoreLines = new Map();
102
- // Settings that control which diagnostics should be output. The rules
103
- // are initialized to the basic set. They should be updated after the
104
- // the file is parsed.
105
- this._diagnosticRuleSet = (0, configOptions_1.getBasicDiagnosticRuleSet)();
94
+ this.parseDiagnostics = [];
95
+ this.commentDiagnostics = [];
96
+ this.bindDiagnostics = [];
97
+ this.checkerDiagnostics = [];
98
+ this.typeIgnoreLines = new Map();
99
+ this.pyrightIgnoreLines = new Map();
106
100
  // Circular dependencies that have been reported in this file.
107
- this._circularDependencies = [];
108
- this._noCircularDependencyConfirmed = false;
101
+ this.circularDependencies = [];
102
+ this.noCircularDependencyConfirmed = false;
109
103
  // Do we need to perform a binding step?
110
- this._isBindingNeeded = true;
104
+ this.isBindingNeeded = true;
111
105
  // Do we have valid diagnostic results from a checking pass?
112
- this._isCheckingNeeded = true;
106
+ this.isCheckingNeeded = true;
113
107
  // Do we need to perform an indexing step?
114
- this._indexingNeeded = true;
108
+ this.indexingNeeded = true;
109
+ // True if the file appears to have been deleted.
110
+ this.isFileDeleted = false;
111
+ }
112
+ }
113
+ class SourceFile {
114
+ constructor(fs, filePath, moduleName, isThirdPartyImport, isThirdPartyPyTypedPresent, editMode, console, logTracker, realFilePath, ipythonMode = IPythonMode.None) {
115
+ // Data that changes when the source file changes.
116
+ this._writableData = new WriteableData();
117
+ // Settings that control which diagnostics should be output. The rules
118
+ // are initialized to the basic set. They should be updated after the
119
+ // the file is parsed.
120
+ this._diagnosticRuleSet = (0, configOptions_1.getBasicDiagnosticRuleSet)();
115
121
  // Indicate whether this file is for ipython or not.
116
122
  this._ipythonMode = IPythonMode.None;
123
+ this._isEditMode = false;
117
124
  this.fileSystem = fs;
118
125
  this._console = console || new console_1.StandardConsole();
126
+ this._isEditMode = editMode;
119
127
  this._filePath = filePath;
120
128
  this._realFilePath = realFilePath !== null && realFilePath !== void 0 ? realFilePath : filePath;
121
129
  this._moduleName = moduleName;
@@ -162,7 +170,7 @@ class SourceFile {
162
170
  this._moduleName = name;
163
171
  }
164
172
  getDiagnosticVersion() {
165
- return this._diagnosticVersion;
173
+ return this._writableData.diagnosticVersion;
166
174
  }
167
175
  isStubFile() {
168
176
  return this._isStubFile;
@@ -174,7 +182,7 @@ class SourceFile {
174
182
  // If the prevVersion is specified, the method returns undefined if
175
183
  // the diagnostics haven't changed.
176
184
  getDiagnostics(options, prevDiagnosticVersion) {
177
- if (this._diagnosticVersion === prevDiagnosticVersion) {
185
+ if (this._writableData.diagnosticVersion === prevDiagnosticVersion) {
178
186
  return undefined;
179
187
  }
180
188
  let includeWarningsAndErrors = true;
@@ -184,23 +192,23 @@ class SourceFile {
184
192
  includeWarningsAndErrors = false;
185
193
  }
186
194
  let diagList = [
187
- ...this._parseDiagnostics,
188
- ...this._commentDiagnostics,
189
- ...this._bindDiagnostics,
190
- ...this._checkerDiagnostics,
195
+ ...this._writableData.parseDiagnostics,
196
+ ...this._writableData.commentDiagnostics,
197
+ ...this._writableData.bindDiagnostics,
198
+ ...this._writableData.checkerDiagnostics,
191
199
  ];
192
200
  const prefilteredDiagList = diagList;
193
- const typeIgnoreLinesClone = new Map(this._typeIgnoreLines);
194
- const pyrightIgnoreLinesClone = new Map(this._pyrightIgnoreLines);
201
+ const typeIgnoreLinesClone = new Map(this._writableData.typeIgnoreLines);
202
+ const pyrightIgnoreLinesClone = new Map(this._writableData.pyrightIgnoreLines);
195
203
  // Filter the diagnostics based on "type: ignore" lines.
196
204
  if (this._diagnosticRuleSet.enableTypeIgnoreComments) {
197
- if (this._typeIgnoreLines.size > 0) {
205
+ if (this._writableData.typeIgnoreLines.size > 0) {
198
206
  diagList = diagList.filter((d) => {
199
207
  if (d.category !== 3 /* UnusedCode */ &&
200
208
  d.category !== 4 /* UnreachableCode */ &&
201
209
  d.category !== 5 /* Deprecated */) {
202
210
  for (let line = d.range.start.line; line <= d.range.end.line; line++) {
203
- if (this._typeIgnoreLines.has(line)) {
211
+ if (this._writableData.typeIgnoreLines.has(line)) {
204
212
  typeIgnoreLinesClone.delete(line);
205
213
  return false;
206
214
  }
@@ -211,11 +219,11 @@ class SourceFile {
211
219
  }
212
220
  }
213
221
  // Filter the diagnostics based on "pyright: ignore" lines.
214
- if (this._pyrightIgnoreLines.size > 0) {
222
+ if (this._writableData.pyrightIgnoreLines.size > 0) {
215
223
  diagList = diagList.filter((d) => {
216
224
  if (d.category !== 4 /* UnreachableCode */ && d.category !== 5 /* Deprecated */) {
217
225
  for (let line = d.range.start.line; line <= d.range.end.line; line++) {
218
- const pyrightIgnoreComment = this._pyrightIgnoreLines.get(line);
226
+ const pyrightIgnoreComment = this._writableData.pyrightIgnoreLines.get(line);
219
227
  if (pyrightIgnoreComment) {
220
228
  if (!pyrightIgnoreComment.rulesList) {
221
229
  pyrightIgnoreLinesClone.delete(line);
@@ -263,20 +271,20 @@ class SourceFile {
263
271
  diag.range.start.line <= range.start.line &&
264
272
  diag.range.end.line >= range.end.line);
265
273
  };
266
- if (prefilteredErrorList.length === 0 && this._typeIgnoreAll !== undefined) {
267
- const rangeStart = this._typeIgnoreAll.range.start;
268
- const rangeEnd = rangeStart + this._typeIgnoreAll.range.length;
269
- const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._parseResults.tokenizerOutput.lines);
274
+ if (prefilteredErrorList.length === 0 && this._writableData.typeIgnoreAll !== undefined) {
275
+ const rangeStart = this._writableData.typeIgnoreAll.range.start;
276
+ const rangeEnd = rangeStart + this._writableData.typeIgnoreAll.range.length;
277
+ const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._writableData.parseResults.tokenizerOutput.lines);
270
278
  if (!isUnreachableCodeRange(range) && this._diagnosticRuleSet.enableTypeIgnoreComments) {
271
279
  unnecessaryTypeIgnoreDiags.push(new diagnostic_1.Diagnostic(diagCategory, localize_1.Localizer.Diagnostic.unnecessaryTypeIgnore(), range));
272
280
  }
273
281
  }
274
282
  typeIgnoreLinesClone.forEach((ignoreComment) => {
275
283
  var _a;
276
- if ((_a = this._parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput.lines) {
284
+ if ((_a = this._writableData.parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput.lines) {
277
285
  const rangeStart = ignoreComment.range.start;
278
286
  const rangeEnd = rangeStart + ignoreComment.range.length;
279
- const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._parseResults.tokenizerOutput.lines);
287
+ const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._writableData.parseResults.tokenizerOutput.lines);
280
288
  if (!isUnreachableCodeRange(range) && this._diagnosticRuleSet.enableTypeIgnoreComments) {
281
289
  unnecessaryTypeIgnoreDiags.push(new diagnostic_1.Diagnostic(diagCategory, localize_1.Localizer.Diagnostic.unnecessaryTypeIgnore(), range));
282
290
  }
@@ -284,11 +292,11 @@ class SourceFile {
284
292
  });
285
293
  pyrightIgnoreLinesClone.forEach((ignoreComment) => {
286
294
  var _a;
287
- if ((_a = this._parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput.lines) {
295
+ if ((_a = this._writableData.parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput.lines) {
288
296
  if (!ignoreComment.rulesList) {
289
297
  const rangeStart = ignoreComment.range.start;
290
298
  const rangeEnd = rangeStart + ignoreComment.range.length;
291
- const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._parseResults.tokenizerOutput.lines);
299
+ const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._writableData.parseResults.tokenizerOutput.lines);
292
300
  if (!isUnreachableCodeRange(range)) {
293
301
  unnecessaryTypeIgnoreDiags.push(new diagnostic_1.Diagnostic(diagCategory, localize_1.Localizer.Diagnostic.unnecessaryPyrightIgnore(), range));
294
302
  }
@@ -297,7 +305,7 @@ class SourceFile {
297
305
  ignoreComment.rulesList.forEach((unusedRule) => {
298
306
  const rangeStart = unusedRule.range.start;
299
307
  const rangeEnd = rangeStart + unusedRule.range.length;
300
- const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._parseResults.tokenizerOutput.lines);
308
+ const range = (0, positionUtils_1.convertOffsetsToRange)(rangeStart, rangeEnd, this._writableData.parseResults.tokenizerOutput.lines);
301
309
  if (!isUnreachableCodeRange(range)) {
302
310
  unnecessaryTypeIgnoreDiags.push(new diagnostic_1.Diagnostic(diagCategory, localize_1.Localizer.Diagnostic.unnecessaryPyrightIgnoreRule().format({
303
311
  name: unusedRule.text,
@@ -308,9 +316,10 @@ class SourceFile {
308
316
  }
309
317
  });
310
318
  }
311
- if (this._diagnosticRuleSet.reportImportCycles !== 'none' && this._circularDependencies.length > 0) {
319
+ if (this._diagnosticRuleSet.reportImportCycles !== 'none' &&
320
+ this._writableData.circularDependencies.length > 0) {
312
321
  const category = (0, diagnostic_1.convertLevelToCategory)(this._diagnosticRuleSet.reportImportCycles);
313
- this._circularDependencies.forEach((cirDep) => {
322
+ this._writableData.circularDependencies.forEach((cirDep) => {
314
323
  const diag = new diagnostic_1.Diagnostic(category, localize_1.Localizer.Diagnostic.importCycleDetected() +
315
324
  '\n' +
316
325
  cirDep
@@ -321,8 +330,8 @@ class SourceFile {
321
330
  diagList.push(diag);
322
331
  });
323
332
  }
324
- if (this._hitMaxImportDepth !== undefined) {
325
- diagList.push(new diagnostic_1.Diagnostic(0 /* Error */, localize_1.Localizer.Diagnostic.importDepthExceeded().format({ depth: this._hitMaxImportDepth }), (0, textRange_1.getEmptyRange)()));
333
+ if (this._writableData.hitMaxImportDepth !== undefined) {
334
+ diagList.push(new diagnostic_1.Diagnostic(0 /* Error */, localize_1.Localizer.Diagnostic.importDepthExceeded().format({ depth: this._writableData.hitMaxImportDepth }), (0, textRange_1.getEmptyRange)()));
326
335
  }
327
336
  // add diagnostics for comments that match the task list tokens
328
337
  this._addTaskListDiagnostics(options.taskListTokens, diagList);
@@ -333,7 +342,7 @@ class SourceFile {
333
342
  // If there is a "type: ignore" comment at the top of the file, clear
334
343
  // the diagnostic list of all error, warning, and information diagnostics.
335
344
  if (this._diagnosticRuleSet.enableTypeIgnoreComments) {
336
- if (this._typeIgnoreAll !== undefined) {
345
+ if (this._writableData.typeIgnoreAll !== undefined) {
337
346
  diagList = diagList.filter((diag) => diag.category !== 0 /* Error */ &&
338
347
  diag.category !== 1 /* Warning */ &&
339
348
  diag.category !== 2 /* Information */);
@@ -352,19 +361,33 @@ class SourceFile {
352
361
  return diagList;
353
362
  }
354
363
  getImports() {
355
- return this._imports || [];
364
+ return this._writableData.imports || [];
356
365
  }
357
366
  getBuiltinsImport() {
358
- return this._builtinsImport;
367
+ return this._writableData.builtinsImport;
359
368
  }
360
369
  getIPythonDisplayImport() {
361
- return this._ipythonDisplayImport;
370
+ return this._writableData.ipythonDisplayImport;
362
371
  }
363
372
  getModuleSymbolTable() {
364
- return this._moduleSymbolTable;
373
+ return this._writableData.moduleSymbolTable;
365
374
  }
366
375
  getCheckTime() {
367
- return this._checkTime;
376
+ return this._writableData.checkTime;
377
+ }
378
+ enterEditMode() {
379
+ this._isEditMode = true;
380
+ }
381
+ exitEditMode() {
382
+ this._isEditMode = false;
383
+ // If we had an edit, return our text.
384
+ if (this._preEditData) {
385
+ const text = this._writableData.clientDocumentContents;
386
+ this._writableData = this._preEditData;
387
+ this._preEditData = undefined;
388
+ return text;
389
+ }
390
+ return undefined;
368
391
  }
369
392
  // Indicates whether the contents of the file have changed since
370
393
  // the last analysis was performed.
@@ -372,11 +395,11 @@ class SourceFile {
372
395
  // If this is an open file any content changes will be
373
396
  // provided through the editor. We can assume contents
374
397
  // didn't change without us knowing about them.
375
- if (this._clientDocumentContents) {
398
+ if (this._writableData.clientDocumentContents) {
376
399
  return false;
377
400
  }
378
401
  // If the file was never read previously, no need to check for a change.
379
- if (this._lastFileContentLength === undefined) {
402
+ if (this._writableData.lastFileContentLength === undefined) {
380
403
  return false;
381
404
  }
382
405
  // Read in the latest file contents and see if the hash matches
@@ -384,10 +407,10 @@ class SourceFile {
384
407
  try {
385
408
  // Read the file's contents.
386
409
  const fileContents = this.fileSystem.readFileSync(this._filePath, 'utf8');
387
- if (fileContents.length !== this._lastFileContentLength) {
410
+ if (fileContents.length !== this._writableData.lastFileContentLength) {
388
411
  return true;
389
412
  }
390
- if (StringUtils.hashString(fileContents) !== this._lastFileContentHash) {
413
+ if (StringUtils.hashString(fileContents) !== this._writableData.lastFileContentHash) {
391
414
  return true;
392
415
  }
393
416
  }
@@ -400,45 +423,45 @@ class SourceFile {
400
423
  // in cases where memory is low. When info is needed, the file
401
424
  // will be re-parsed and rebound.
402
425
  dropParseAndBindInfo() {
403
- this._parseResults = undefined;
404
- this._moduleSymbolTable = undefined;
405
- this._isBindingNeeded = true;
426
+ this._writableData.parseResults = undefined;
427
+ this._writableData.moduleSymbolTable = undefined;
428
+ this._writableData.isBindingNeeded = true;
406
429
  }
407
430
  markDirty(indexingNeeded = true) {
408
- this._fileContentsVersion++;
409
- this._noCircularDependencyConfirmed = false;
410
- this._isCheckingNeeded = true;
411
- this._isBindingNeeded = true;
412
- this._indexingNeeded = indexingNeeded;
413
- this._moduleSymbolTable = undefined;
414
- this._cachedIndexResults = undefined;
431
+ this._writableData.fileContentsVersion++;
432
+ this._writableData.noCircularDependencyConfirmed = false;
433
+ this._writableData.isCheckingNeeded = true;
434
+ this._writableData.isBindingNeeded = true;
435
+ this._writableData.indexingNeeded = indexingNeeded;
436
+ this._writableData.moduleSymbolTable = undefined;
437
+ this._writableData.cachedIndexResults = undefined;
415
438
  const filePath = this.getFilePath();
416
439
  extensibility_1.Extensions.getProgramExtensions(filePath).forEach((e) => (e.fileDirty ? e.fileDirty(filePath) : null));
417
440
  }
418
441
  markReanalysisRequired(forceRebinding) {
419
442
  // Keep the parse info, but reset the analysis to the beginning.
420
- this._isCheckingNeeded = true;
421
- this._noCircularDependencyConfirmed = false;
443
+ this._writableData.isCheckingNeeded = true;
444
+ this._writableData.noCircularDependencyConfirmed = false;
422
445
  // If the file contains a wildcard import or __all__ symbols,
423
446
  // we need to rebind because a dependent import may have changed.
424
- if (this._parseResults) {
425
- if (this._parseResults.containsWildcardImport ||
426
- AnalyzerNodeInfo.getDunderAllInfo(this._parseResults.parseTree) !== undefined ||
447
+ if (this._writableData.parseResults) {
448
+ if (this._writableData.parseResults.containsWildcardImport ||
449
+ AnalyzerNodeInfo.getDunderAllInfo(this._writableData.parseResults.parseTree) !== undefined ||
427
450
  forceRebinding) {
428
451
  // We don't need to rebuild index data since wildcard
429
452
  // won't affect user file indices. User file indices
430
453
  // don't contain import alias info.
431
- this._parseTreeNeedsCleaning = true;
432
- this._isBindingNeeded = true;
433
- this._moduleSymbolTable = undefined;
454
+ this._writableData.parseTreeNeedsCleaning = true;
455
+ this._writableData.isBindingNeeded = true;
456
+ this._writableData.moduleSymbolTable = undefined;
434
457
  }
435
458
  }
436
459
  }
437
460
  getClientVersion() {
438
- return this._clientDocumentVersion;
461
+ return this._writableData.clientDocumentVersion;
439
462
  }
440
463
  getOpenFileContents() {
441
- return this._clientDocumentContents;
464
+ return this._writableData.clientDocumentContents;
442
465
  }
443
466
  getFileContent() {
444
467
  // Get current buffer content if the file is opened.
@@ -462,82 +485,86 @@ class SourceFile {
462
485
  }
463
486
  }
464
487
  setClientVersion(version, contents) {
488
+ // Save pre edit state if in edit mode.
489
+ this._cachePreEditState();
465
490
  if (version === null) {
466
- this._clientDocumentVersion = undefined;
467
- this._clientDocumentContents = undefined;
491
+ this._writableData.clientDocumentVersion = undefined;
492
+ this._writableData.clientDocumentContents = undefined;
468
493
  }
469
494
  else {
470
- this._clientDocumentVersion = version;
471
- this._clientDocumentContents = contents;
495
+ this._writableData.clientDocumentVersion = version;
496
+ this._writableData.clientDocumentContents = contents;
472
497
  const contentsHash = StringUtils.hashString(contents);
473
498
  // Have the contents of the file changed?
474
- if (contents.length !== this._lastFileContentLength || contentsHash !== this._lastFileContentHash) {
499
+ if (contents.length !== this._writableData.lastFileContentLength ||
500
+ contentsHash !== this._writableData.lastFileContentHash) {
475
501
  this.markDirty();
476
502
  }
477
- this._lastFileContentLength = contents.length;
478
- this._lastFileContentHash = contentsHash;
479
- this._isFileDeleted = false;
503
+ this._writableData.lastFileContentLength = contents.length;
504
+ this._writableData.lastFileContentHash = contentsHash;
505
+ this._writableData.isFileDeleted = false;
480
506
  }
481
507
  }
482
508
  prepareForClose() {
483
509
  // Nothing to do currently.
484
510
  }
485
511
  isFileDeleted() {
486
- return this._isFileDeleted;
512
+ return this._writableData.isFileDeleted;
487
513
  }
488
514
  isParseRequired() {
489
- return !this._parseResults || this._analyzedFileContentsVersion !== this._fileContentsVersion;
515
+ return (!this._writableData.parseResults ||
516
+ this._writableData.analyzedFileContentsVersion !== this._writableData.fileContentsVersion);
490
517
  }
491
518
  isBindingRequired() {
492
- if (this._isBindingInProgress) {
519
+ if (this._writableData.isBindingInProgress) {
493
520
  return false;
494
521
  }
495
522
  if (this.isParseRequired()) {
496
523
  return true;
497
524
  }
498
- return this._isBindingNeeded;
525
+ return this._writableData.isBindingNeeded;
499
526
  }
500
527
  isIndexingRequired() {
501
- return this._indexingNeeded;
528
+ return this._writableData.indexingNeeded;
502
529
  }
503
530
  isCheckingRequired() {
504
- return this._isCheckingNeeded;
531
+ return this._writableData.isCheckingNeeded;
505
532
  }
506
533
  getParseResults() {
507
534
  if (!this.isParseRequired()) {
508
- return this._parseResults;
535
+ return this._writableData.parseResults;
509
536
  }
510
537
  return undefined;
511
538
  }
512
539
  getCachedIndexResults() {
513
- return this._cachedIndexResults;
540
+ return this._writableData.cachedIndexResults;
514
541
  }
515
542
  cacheIndexResults(indexResults) {
516
- this._cachedIndexResults = indexResults;
543
+ this._writableData.cachedIndexResults = indexResults;
517
544
  }
518
545
  // Adds a new circular dependency for this file but only if
519
546
  // it hasn't already been added.
520
547
  addCircularDependency(circDependency) {
521
548
  let updatedDependencyList = false;
522
549
  // Some topologies can result in a massive number of cycles. We'll cut it off.
523
- if (this._circularDependencies.length < _maxImportCyclesPerFile) {
524
- if (!this._circularDependencies.some((dep) => dep.isEqual(circDependency))) {
525
- this._circularDependencies.push(circDependency);
550
+ if (this._writableData.circularDependencies.length < _maxImportCyclesPerFile) {
551
+ if (!this._writableData.circularDependencies.some((dep) => dep.isEqual(circDependency))) {
552
+ this._writableData.circularDependencies.push(circDependency);
526
553
  updatedDependencyList = true;
527
554
  }
528
555
  }
529
556
  if (updatedDependencyList) {
530
- this._diagnosticVersion++;
557
+ this._writableData.diagnosticVersion++;
531
558
  }
532
559
  }
533
560
  setNoCircularDependencyConfirmed() {
534
- this._noCircularDependencyConfirmed = true;
561
+ this._writableData.noCircularDependencyConfirmed = true;
535
562
  }
536
563
  isNoCircularDependencyConfirmed() {
537
- return !this.isParseRequired() && this._noCircularDependencyConfirmed;
564
+ return !this.isParseRequired() && this._writableData.noCircularDependencyConfirmed;
538
565
  }
539
566
  setHitMaxImportDepth(maxImportDepth) {
540
- this._hitMaxImportDepth = maxImportDepth;
567
+ this._writableData.hitMaxImportDepth = maxImportDepth;
541
568
  }
542
569
  // Parse the file and update the state. Callers should wait for completion
543
570
  // (or at least cancel) prior to calling again. It returns true if a parse
@@ -561,8 +588,8 @@ class SourceFile {
561
588
  throw new Error("Can't get file content");
562
589
  }
563
590
  // Remember the length and hash for comparison purposes.
564
- this._lastFileContentLength = fileContents.length;
565
- this._lastFileContentHash = StringUtils.hashString(fileContents);
591
+ this._writableData.lastFileContentLength = fileContents.length;
592
+ this._writableData.lastFileContentHash = StringUtils.hashString(fileContents);
566
593
  });
567
594
  logState.add(`fs read ${timing_1.timingStats.readFileTime.totalTime - startTime}ms`);
568
595
  }
@@ -570,7 +597,7 @@ class SourceFile {
570
597
  diagSink.addError(`Source file could not be read`, (0, textRange_1.getEmptyRange)());
571
598
  fileContents = '';
572
599
  if (!this.fileSystem.existsSync(this._realFilePath)) {
573
- this._isFileDeleted = true;
600
+ this._writableData.isFileDeleted = true;
574
601
  }
575
602
  }
576
603
  }
@@ -578,27 +605,28 @@ class SourceFile {
578
605
  // Parse the token stream, building the abstract syntax tree.
579
606
  const parseResults = parseFile(configOptions, this._filePath, fileContents, this._ipythonMode, diagSink);
580
607
  (0, debug_1.assert)(parseResults !== undefined && parseResults.tokenizerOutput !== undefined);
581
- this._parseResults = parseResults;
582
- this._typeIgnoreLines = this._parseResults.tokenizerOutput.typeIgnoreLines;
583
- this._typeIgnoreAll = this._parseResults.tokenizerOutput.typeIgnoreAll;
584
- this._pyrightIgnoreLines = this._parseResults.tokenizerOutput.pyrightIgnoreLines;
608
+ this._writableData.parseResults = parseResults;
609
+ this._writableData.typeIgnoreLines = this._writableData.parseResults.tokenizerOutput.typeIgnoreLines;
610
+ this._writableData.typeIgnoreAll = this._writableData.parseResults.tokenizerOutput.typeIgnoreAll;
611
+ this._writableData.pyrightIgnoreLines =
612
+ this._writableData.parseResults.tokenizerOutput.pyrightIgnoreLines;
585
613
  // Resolve imports.
586
614
  const execEnvironment = configOptions.findExecEnvironment(this._filePath);
587
615
  timing_1.timingStats.resolveImportsTime.timeOperation(() => {
588
616
  const importResult = this._resolveImports(importResolver, parseResults.importedModules, execEnvironment);
589
- this._imports = importResult.imports;
590
- this._builtinsImport = importResult.builtinsImportResult;
591
- this._ipythonDisplayImport = importResult.ipythonDisplayImportResult;
592
- this._parseDiagnostics = diagSink.fetchAndClear();
617
+ this._writableData.imports = importResult.imports;
618
+ this._writableData.builtinsImport = importResult.builtinsImportResult;
619
+ this._writableData.ipythonDisplayImport = importResult.ipythonDisplayImportResult;
620
+ this._writableData.parseDiagnostics = diagSink.fetchAndClear();
593
621
  });
594
622
  // Is this file in a "strict" path?
595
623
  const useStrict = configOptions.strict.find((strictFileSpec) => strictFileSpec.regExp.test(this._realFilePath)) !==
596
624
  undefined;
597
625
  const commentDiags = [];
598
- this._diagnosticRuleSet = CommentUtils.getFileLevelDirectives(this._parseResults.tokenizerOutput.tokens, this._parseResults.tokenizerOutput.lines, configOptions.diagnosticRuleSet, useStrict, commentDiags);
599
- this._commentDiagnostics = [];
626
+ this._diagnosticRuleSet = CommentUtils.getFileLevelDirectives(this._writableData.parseResults.tokenizerOutput.tokens, this._writableData.parseResults.tokenizerOutput.lines, configOptions.diagnosticRuleSet, useStrict, commentDiags);
627
+ this._writableData.commentDiagnostics = [];
600
628
  commentDiags.forEach((commentDiag) => {
601
- this._commentDiagnostics.push(new diagnostic_1.Diagnostic(0 /* Error */, commentDiag.message, (0, positionUtils_1.convertTextRangeToRange)(commentDiag.range, this._parseResults.tokenizerOutput.lines)));
629
+ this._writableData.commentDiagnostics.push(new diagnostic_1.Diagnostic(0 /* Error */, commentDiag.message, (0, positionUtils_1.convertTextRangeToRange)(commentDiag.range, this._writableData.parseResults.tokenizerOutput.lines)));
602
630
  });
603
631
  }
604
632
  catch (e) {
@@ -607,7 +635,7 @@ class SourceFile {
607
635
  JSON.stringify(e);
608
636
  this._console.error(localize_1.Localizer.Diagnostic.internalParseError().format({ file: this.getFilePath(), message }));
609
637
  // Create dummy parse results.
610
- this._parseResults = {
638
+ this._writableData.parseResults = {
611
639
  text: '',
612
640
  parseTree: parseNodes_1.ModuleNode.create({ start: 0, length: 0 }),
613
641
  importedModules: [],
@@ -625,34 +653,34 @@ class SourceFile {
625
653
  containsWildcardImport: false,
626
654
  typingSymbolAliases: new Map(),
627
655
  };
628
- this._imports = undefined;
629
- this._builtinsImport = undefined;
630
- this._ipythonDisplayImport = undefined;
656
+ this._writableData.imports = undefined;
657
+ this._writableData.builtinsImport = undefined;
658
+ this._writableData.ipythonDisplayImport = undefined;
631
659
  const diagSink = new diagnosticSink_1.DiagnosticSink();
632
660
  diagSink.addError(localize_1.Localizer.Diagnostic.internalParseError().format({ file: this.getFilePath(), message }), (0, textRange_1.getEmptyRange)());
633
- this._parseDiagnostics = diagSink.fetchAndClear();
661
+ this._writableData.parseDiagnostics = diagSink.fetchAndClear();
634
662
  // Do not rethrow the exception, swallow it here. Callers are not
635
663
  // prepared to handle an exception.
636
664
  }
637
- this._analyzedFileContentsVersion = this._fileContentsVersion;
638
- this._indexingNeeded = true;
639
- this._isBindingNeeded = true;
640
- this._isCheckingNeeded = true;
641
- this._parseTreeNeedsCleaning = false;
642
- this._hitMaxImportDepth = undefined;
643
- this._diagnosticVersion++;
665
+ this._writableData.analyzedFileContentsVersion = this._writableData.fileContentsVersion;
666
+ this._writableData.indexingNeeded = true;
667
+ this._writableData.isBindingNeeded = true;
668
+ this._writableData.isCheckingNeeded = true;
669
+ this._writableData.parseTreeNeedsCleaning = false;
670
+ this._writableData.hitMaxImportDepth = undefined;
671
+ this._writableData.diagnosticVersion++;
644
672
  return true;
645
673
  });
646
674
  }
647
675
  index(options, token) {
648
676
  return this._logTracker.log(`indexing: ${this._getPathForLogging(this._filePath)}`, (ls) => {
649
677
  // If we have no completed analysis job, there's nothing to do.
650
- if (!this._parseResults || !this.isIndexingRequired()) {
678
+ if (!this._writableData.parseResults || !this.isIndexingRequired()) {
651
679
  ls.suppress();
652
680
  return undefined;
653
681
  }
654
- this._indexingNeeded = false;
655
- const symbols = documentSymbolProvider_1.DocumentSymbolProvider.indexSymbols(AnalyzerNodeInfo.getFileInfo(this._parseResults.parseTree), this._parseResults, options, token);
682
+ this._writableData.indexingNeeded = false;
683
+ const symbols = documentSymbolProvider_1.DocumentSymbolProvider.indexSymbols(AnalyzerNodeInfo.getFileInfo(this._writableData.parseResults.parseTree), this._writableData.parseResults, options, token);
656
684
  ls.add(`found ${symbols.length}`);
657
685
  const name = (0, pathUtils_1.stripFileExtension)((0, pathUtils_1.getFileName)(this._filePath));
658
686
  const privateOrProtected = SymbolNameUtils.isPrivateOrProtectedName(name);
@@ -661,21 +689,25 @@ class SourceFile {
661
689
  }
662
690
  addHierarchicalSymbolsForDocument(symbolList, token) {
663
691
  // If we have no completed analysis job, there's nothing to do.
664
- if (!this._parseResults && !this._cachedIndexResults) {
692
+ if (!this._writableData.parseResults && !this._writableData.cachedIndexResults) {
665
693
  return;
666
694
  }
667
- documentSymbolProvider_1.DocumentSymbolProvider.addHierarchicalSymbolsForDocument(this._parseResults ? AnalyzerNodeInfo.getFileInfo(this._parseResults.parseTree) : undefined, this.getCachedIndexResults(), this._parseResults, symbolList, token);
695
+ documentSymbolProvider_1.DocumentSymbolProvider.addHierarchicalSymbolsForDocument(this._writableData.parseResults
696
+ ? AnalyzerNodeInfo.getFileInfo(this._writableData.parseResults.parseTree)
697
+ : undefined, this.getCachedIndexResults(), this._writableData.parseResults, symbolList, token);
668
698
  }
669
699
  getSymbolsForDocument(query, token) {
670
700
  // If we have no completed analysis job, there's nothing to do.
671
- if (!this._parseResults && !this._cachedIndexResults) {
701
+ if (!this._writableData.parseResults && !this._writableData.cachedIndexResults) {
672
702
  return [];
673
703
  }
674
- return documentSymbolProvider_1.DocumentSymbolProvider.getSymbolsForDocument(this._parseResults ? AnalyzerNodeInfo.getFileInfo(this._parseResults.parseTree) : undefined, this.getCachedIndexResults(), this._parseResults, this._filePath, query, token);
704
+ return documentSymbolProvider_1.DocumentSymbolProvider.getSymbolsForDocument(this._writableData.parseResults
705
+ ? AnalyzerNodeInfo.getFileInfo(this._writableData.parseResults.parseTree)
706
+ : undefined, this.getCachedIndexResults(), this._writableData.parseResults, this._filePath, query, token);
675
707
  }
676
- getCompletionsForPosition(position, workspacePath, configOptions, importResolver, importLookup, evaluator, options, sourceMapper, nameMap, libraryMap, moduleSymbolsCallback, token) {
708
+ getCompletionsForPosition(program, position, workspacePath, importLookup, options, nameMap, libraryMap, moduleSymbolsCallback, token) {
677
709
  // If we have no completed analysis job, there's nothing to do.
678
- if (!this._parseResults) {
710
+ if (!this._writableData.parseResults) {
679
711
  return undefined;
680
712
  }
681
713
  // This command should be called only for open files, in which
@@ -684,20 +716,20 @@ class SourceFile {
684
716
  if (fileContents === undefined) {
685
717
  return undefined;
686
718
  }
687
- const completionProvider = new completionProvider_1.CompletionProvider(workspacePath, this._parseResults, fileContents, importResolver, position, this._filePath, configOptions, importLookup, evaluator, options, sourceMapper, {
719
+ const completionProvider = new completionProvider_1.CompletionProvider(program, workspacePath, this._filePath, position, importLookup, options, {
688
720
  nameMap,
689
721
  libraryMap,
690
722
  getModuleSymbolsMap: moduleSymbolsCallback,
691
723
  }, token);
692
724
  return completionProvider.getCompletionsForPosition();
693
725
  }
694
- resolveCompletionItem(configOptions, importResolver, importLookup, evaluator, options, sourceMapper, nameMap, libraryMap, moduleSymbolsCallback, completionItem, token) {
726
+ resolveCompletionItem(program, importLookup, options, nameMap, libraryMap, moduleSymbolsCallback, completionItem, token) {
695
727
  const fileContents = this.getOpenFileContents();
696
- if (!this._parseResults || fileContents === undefined) {
728
+ if (!this._writableData.parseResults || fileContents === undefined) {
697
729
  return;
698
730
  }
699
731
  const completionData = (0, lspUtils_1.fromLSPAny)(completionItem.data);
700
- const completionProvider = new completionProvider_1.CompletionProvider(completionData.workspacePath, this._parseResults, fileContents, importResolver, completionData.position, this._filePath, configOptions, importLookup, evaluator, options, sourceMapper, {
732
+ const completionProvider = new completionProvider_1.CompletionProvider(program, completionData.workspacePath, this._filePath, completionData.position, importLookup, options, {
701
733
  nameMap,
702
734
  libraryMap,
703
735
  getModuleSymbolsMap: moduleSymbolsCallback,
@@ -707,28 +739,28 @@ class SourceFile {
707
739
  bind(configOptions, importLookup, builtinsScope, futureImports) {
708
740
  (0, debug_1.assert)(!this.isParseRequired(), 'Bind called before parsing');
709
741
  (0, debug_1.assert)(this.isBindingRequired(), 'Bind called unnecessarily');
710
- (0, debug_1.assert)(!this._isBindingInProgress, 'Bind called while binding in progress');
711
- (0, debug_1.assert)(this._parseResults !== undefined, 'Parse results not available');
742
+ (0, debug_1.assert)(!this._writableData.isBindingInProgress, 'Bind called while binding in progress');
743
+ (0, debug_1.assert)(this._writableData.parseResults !== undefined, 'Parse results not available');
712
744
  return this._logTracker.log(`binding: ${this._getPathForLogging(this._filePath)}`, () => {
713
745
  try {
714
746
  // Perform name binding.
715
747
  timing_1.timingStats.bindTime.timeOperation(() => {
716
748
  this._cleanParseTreeIfRequired();
717
- const fileInfo = this._buildFileInfo(configOptions, this._parseResults.text, importLookup, builtinsScope, futureImports);
718
- AnalyzerNodeInfo.setFileInfo(this._parseResults.parseTree, fileInfo);
749
+ const fileInfo = this._buildFileInfo(configOptions, this._writableData.parseResults.text, importLookup, builtinsScope, futureImports);
750
+ AnalyzerNodeInfo.setFileInfo(this._writableData.parseResults.parseTree, fileInfo);
719
751
  const binder = new binder_1.Binder(fileInfo, configOptions.indexGenerationMode);
720
- this._isBindingInProgress = true;
721
- binder.bindModule(this._parseResults.parseTree);
752
+ this._writableData.isBindingInProgress = true;
753
+ binder.bindModule(this._writableData.parseResults.parseTree);
722
754
  // If we're in "test mode" (used for unit testing), run an additional
723
755
  // "test walker" over the parse tree to validate its internal consistency.
724
756
  if (configOptions.internalTestMode) {
725
757
  const testWalker = new testWalker_1.TestWalker();
726
- testWalker.walk(this._parseResults.parseTree);
758
+ testWalker.walk(this._writableData.parseResults.parseTree);
727
759
  }
728
- this._bindDiagnostics = fileInfo.diagnosticSink.fetchAndClear();
729
- const moduleScope = AnalyzerNodeInfo.getScope(this._parseResults.parseTree);
760
+ this._writableData.bindDiagnostics = fileInfo.diagnosticSink.fetchAndClear();
761
+ const moduleScope = AnalyzerNodeInfo.getScope(this._writableData.parseResults.parseTree);
730
762
  (0, debug_1.assert)(moduleScope !== undefined, 'Module scope not returned by binder');
731
- this._moduleSymbolTable = moduleScope.symbolTable;
763
+ this._writableData.moduleSymbolTable = moduleScope.symbolTable;
732
764
  });
733
765
  }
734
766
  catch (e) {
@@ -738,36 +770,36 @@ class SourceFile {
738
770
  this._console.error(localize_1.Localizer.Diagnostic.internalBindError().format({ file: this.getFilePath(), message }));
739
771
  const diagSink = new diagnosticSink_1.DiagnosticSink();
740
772
  diagSink.addError(localize_1.Localizer.Diagnostic.internalBindError().format({ file: this.getFilePath(), message }), (0, textRange_1.getEmptyRange)());
741
- this._bindDiagnostics = diagSink.fetchAndClear();
773
+ this._writableData.bindDiagnostics = diagSink.fetchAndClear();
742
774
  // Do not rethrow the exception, swallow it here. Callers are not
743
775
  // prepared to handle an exception.
744
776
  }
745
777
  finally {
746
- this._isBindingInProgress = false;
778
+ this._writableData.isBindingInProgress = false;
747
779
  }
748
780
  // Prepare for the next stage of the analysis.
749
- this._diagnosticVersion++;
750
- this._isCheckingNeeded = true;
751
- this._indexingNeeded = true;
752
- this._isBindingNeeded = false;
781
+ this._writableData.diagnosticVersion++;
782
+ this._writableData.isCheckingNeeded = true;
783
+ this._writableData.indexingNeeded = true;
784
+ this._writableData.isBindingNeeded = false;
753
785
  });
754
786
  }
755
787
  check(importResolver, evaluator, sourceMapper, dependentFiles) {
756
788
  (0, debug_1.assert)(!this.isParseRequired(), 'Check called before parsing');
757
789
  (0, debug_1.assert)(!this.isBindingRequired(), 'Check called before binding');
758
- (0, debug_1.assert)(!this._isBindingInProgress, 'Check called while binding in progress');
790
+ (0, debug_1.assert)(!this._writableData.isBindingInProgress, 'Check called while binding in progress');
759
791
  (0, debug_1.assert)(this.isCheckingRequired(), 'Check called unnecessarily');
760
- (0, debug_1.assert)(this._parseResults !== undefined, 'Parse results not available');
792
+ (0, debug_1.assert)(this._writableData.parseResults !== undefined, 'Parse results not available');
761
793
  return this._logTracker.log(`checking: ${this._getPathForLogging(this._filePath)}`, () => {
762
794
  try {
763
795
  timing_1.timingStats.typeCheckerTime.timeOperation(() => {
764
796
  const checkDuration = new timing_1.Duration();
765
- const checker = new checker_1.Checker(importResolver, evaluator, this._parseResults, sourceMapper, dependentFiles);
797
+ const checker = new checker_1.Checker(importResolver, evaluator, this._writableData.parseResults, sourceMapper, dependentFiles);
766
798
  checker.check();
767
- this._isCheckingNeeded = false;
768
- const fileInfo = AnalyzerNodeInfo.getFileInfo(this._parseResults.parseTree);
769
- this._checkerDiagnostics = fileInfo.diagnosticSink.fetchAndClear();
770
- this._checkTime = checkDuration.getDurationInMilliseconds();
799
+ this._writableData.isCheckingNeeded = false;
800
+ const fileInfo = AnalyzerNodeInfo.getFileInfo(this._writableData.parseResults.parseTree);
801
+ this._writableData.checkerDiagnostics = fileInfo.diagnosticSink.fetchAndClear();
802
+ this._writableData.checkTime = checkDuration.getDurationInMilliseconds();
771
803
  });
772
804
  }
773
805
  catch (e) {
@@ -779,9 +811,9 @@ class SourceFile {
779
811
  this._console.error(localize_1.Localizer.Diagnostic.internalTypeCheckingError().format({ file: this.getFilePath(), message }));
780
812
  const diagSink = new diagnosticSink_1.DiagnosticSink();
781
813
  diagSink.addError(localize_1.Localizer.Diagnostic.internalTypeCheckingError().format({ file: this.getFilePath(), message }), (0, textRange_1.getEmptyRange)());
782
- this._checkerDiagnostics = diagSink.fetchAndClear();
814
+ this._writableData.checkerDiagnostics = diagSink.fetchAndClear();
783
815
  // Mark the file as complete so we don't get into an infinite loop.
784
- this._isCheckingNeeded = false;
816
+ this._writableData.isCheckingNeeded = false;
785
817
  }
786
818
  throw e;
787
819
  }
@@ -789,14 +821,26 @@ class SourceFile {
789
821
  // Clear any circular dependencies associated with this file.
790
822
  // These will be detected by the program module and associated
791
823
  // with the source file right before it is finalized.
792
- this._circularDependencies = [];
793
- this._diagnosticVersion++;
824
+ this._writableData.circularDependencies = [];
825
+ this._writableData.diagnosticVersion++;
794
826
  }
795
827
  });
796
828
  }
797
829
  test_enableIPythonMode(enable) {
798
830
  this._ipythonMode = enable ? IPythonMode.CellDocs : IPythonMode.None;
799
831
  }
832
+ _cachePreEditState() {
833
+ // If there's no document yet, this change doesn't count as a write yet.
834
+ if (this._writableData.clientDocumentContents !== undefined) {
835
+ // If this is our first write, then make a copy of the writable data.
836
+ if (this._isEditMode && !this._preEditData) {
837
+ // Copy over the writable data.
838
+ this._preEditData = this._writableData;
839
+ // Recreate all the writable data from scratch.
840
+ this._writableData = new WriteableData();
841
+ }
842
+ }
843
+ }
800
844
  // Get all task list diagnostics for the current file and add them
801
845
  // to the specified diagnostic list
802
846
  _addTaskListDiagnostics(taskListTokens, diagList) {
@@ -806,10 +850,10 @@ class SourceFile {
806
850
  return;
807
851
  }
808
852
  // if we have no tokens, we're done
809
- if (!((_b = (_a = this._parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput) === null || _b === void 0 ? void 0 : _b.tokens)) {
853
+ if (!((_b = (_a = this._writableData.parseResults) === null || _a === void 0 ? void 0 : _a.tokenizerOutput) === null || _b === void 0 ? void 0 : _b.tokens)) {
810
854
  return;
811
855
  }
812
- const tokenizerOutput = this._parseResults.tokenizerOutput;
856
+ const tokenizerOutput = this._writableData.parseResults.tokenizerOutput;
813
857
  for (let i = 0; i < tokenizerOutput.tokens.count; i++) {
814
858
  const token = tokenizerOutput.tokens.getItemAt(i);
815
859
  // if there are no comments, skip this token
@@ -845,8 +889,8 @@ class SourceFile {
845
889
  }
846
890
  }
847
891
  _buildFileInfo(configOptions, fileContents, importLookup, builtinsScope, futureImports) {
848
- (0, debug_1.assert)(this._parseResults !== undefined, 'Parse results not available');
849
- const analysisDiagnostics = new diagnosticSink_1.TextRangeDiagnosticSink(this._parseResults.tokenizerOutput.lines);
892
+ (0, debug_1.assert)(this._writableData.parseResults !== undefined, 'Parse results not available');
893
+ const analysisDiagnostics = new diagnosticSink_1.TextRangeDiagnosticSink(this._writableData.parseResults.tokenizerOutput.lines);
850
894
  const fileInfo = {
851
895
  importLookup,
852
896
  futureImports,
@@ -855,8 +899,8 @@ class SourceFile {
855
899
  executionEnvironment: configOptions.findExecEnvironment(this._filePath),
856
900
  diagnosticRuleSet: this._diagnosticRuleSet,
857
901
  fileContents,
858
- lines: this._parseResults.tokenizerOutput.lines,
859
- typingSymbolAliases: this._parseResults.typingSymbolAliases,
902
+ lines: this._writableData.parseResults.tokenizerOutput.lines,
903
+ typingSymbolAliases: this._writableData.parseResults.typingSymbolAliases,
860
904
  definedConstants: configOptions.defineConstant,
861
905
  filePath: this._filePath,
862
906
  moduleName: this._moduleName,
@@ -871,11 +915,11 @@ class SourceFile {
871
915
  return fileInfo;
872
916
  }
873
917
  _cleanParseTreeIfRequired() {
874
- if (this._parseResults) {
875
- if (this._parseTreeNeedsCleaning) {
876
- const cleanerWalker = new parseTreeCleaner_1.ParseTreeCleanerWalker(this._parseResults.parseTree);
918
+ if (this._writableData.parseResults) {
919
+ if (this._writableData.parseTreeNeedsCleaning) {
920
+ const cleanerWalker = new parseTreeCleaner_1.ParseTreeCleanerWalker(this._writableData.parseResults.parseTree);
877
921
  cleanerWalker.clean();
878
- this._parseTreeNeedsCleaning = false;
922
+ this._writableData.parseTreeNeedsCleaning = false;
879
923
  }
880
924
  }
881
925
  }