@zzzen/pyright-internal 1.2.0-dev.20230219 → 1.2.0-dev.20230305
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.
- package/dist/analyzer/backgroundAnalysisProgram.d.ts +1 -1
- package/dist/analyzer/backgroundAnalysisProgram.js +3 -3
- package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
- package/dist/analyzer/binder.d.ts +0 -1
- package/dist/analyzer/binder.js +18 -93
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/checker.js +50 -30
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/codeFlowEngine.js +5 -5
- package/dist/analyzer/codeFlowEngine.js.map +1 -1
- package/dist/analyzer/constraintSolver.js +0 -10
- package/dist/analyzer/constraintSolver.js.map +1 -1
- package/dist/analyzer/declaration.d.ts +3 -4
- package/dist/analyzer/declaration.js +6 -1
- package/dist/analyzer/declaration.js.map +1 -1
- package/dist/analyzer/declarationUtils.d.ts +1 -5
- package/dist/analyzer/declarationUtils.js +2 -47
- package/dist/analyzer/declarationUtils.js.map +1 -1
- package/dist/analyzer/docStringConversion.js +9 -3
- package/dist/analyzer/docStringConversion.js.map +1 -1
- package/dist/analyzer/importResolver.d.ts +3 -2
- package/dist/analyzer/importResolver.js +28 -19
- package/dist/analyzer/importResolver.js.map +1 -1
- package/dist/analyzer/parseTreeUtils.d.ts +4 -2
- package/dist/analyzer/parseTreeUtils.js +77 -2
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/patternMatching.d.ts +1 -0
- package/dist/analyzer/patternMatching.js +47 -2
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/program.d.ts +5 -4
- package/dist/analyzer/program.js +182 -43
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/properties.js +8 -3
- package/dist/analyzer/properties.js.map +1 -1
- package/dist/analyzer/protocols.js +8 -5
- package/dist/analyzer/protocols.js.map +1 -1
- package/dist/analyzer/pythonPathUtils.js +27 -13
- package/dist/analyzer/pythonPathUtils.js.map +1 -1
- package/dist/analyzer/service.d.ts +7 -3
- package/dist/analyzer/service.js +24 -7
- package/dist/analyzer/service.js.map +1 -1
- package/dist/analyzer/sourceFile.js +3 -0
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/symbol.js +1 -4
- package/dist/analyzer/symbol.js.map +1 -1
- package/dist/analyzer/symbolUtils.d.ts +0 -3
- package/dist/analyzer/symbolUtils.js +1 -14
- package/dist/analyzer/symbolUtils.js.map +1 -1
- package/dist/analyzer/typeDocStringUtils.js +5 -3
- package/dist/analyzer/typeDocStringUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator.js +586 -294
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +10 -2
- package/dist/analyzer/typeGuards.js +2 -2
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typeUtils.d.ts +1 -0
- package/dist/analyzer/typeUtils.js +14 -1
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typedDicts.js +26 -17
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +2 -1
- package/dist/analyzer/types.js.map +1 -1
- package/dist/backgroundAnalysisBase.d.ts +2 -3
- package/dist/backgroundAnalysisBase.js +12 -13
- package/dist/backgroundAnalysisBase.js.map +1 -1
- package/dist/commands/commandController.js +1 -0
- package/dist/commands/commandController.js.map +1 -1
- package/dist/commands/quickActionCommand.js +2 -2
- package/dist/commands/quickActionCommand.js.map +1 -1
- package/dist/common/cancellationUtils.d.ts +18 -2
- package/dist/common/cancellationUtils.js +80 -3
- package/dist/common/cancellationUtils.js.map +1 -1
- package/dist/common/collectionUtils.d.ts +1 -0
- package/dist/common/collectionUtils.js +8 -1
- package/dist/common/collectionUtils.js.map +1 -1
- package/dist/common/extensibility.d.ts +4 -3
- package/dist/common/extensibility.js.map +1 -1
- package/dist/common/fileBasedCancellationUtils.d.ts +0 -1
- package/dist/common/fileBasedCancellationUtils.js +7 -81
- package/dist/common/fileBasedCancellationUtils.js.map +1 -1
- package/dist/common/positionUtils.d.ts +2 -0
- package/dist/common/positionUtils.js +15 -1
- package/dist/common/positionUtils.js.map +1 -1
- package/dist/common/{textEditUtils.d.ts → textEditTracker.d.ts} +2 -6
- package/dist/common/{textEditUtils.js → textEditTracker.js} +6 -49
- package/dist/common/textEditTracker.js.map +1 -0
- package/dist/common/workspaceEditUtils.d.ts +14 -8
- package/dist/common/workspaceEditUtils.js +115 -59
- package/dist/common/workspaceEditUtils.js.map +1 -1
- package/dist/languageServerBase.js +9 -3
- package/dist/languageServerBase.js.map +1 -1
- package/dist/languageService/callHierarchyProvider.js +4 -2
- package/dist/languageService/callHierarchyProvider.js.map +1 -1
- package/dist/languageService/codeActionProvider.js +1 -1
- package/dist/languageService/codeActionProvider.js.map +1 -1
- package/dist/languageService/completionProvider.js +49 -43
- package/dist/languageService/completionProvider.js.map +1 -1
- package/dist/languageService/completionProviderUtils.d.ts +1 -1
- package/dist/languageService/completionProviderUtils.js +3 -3
- package/dist/languageService/completionProviderUtils.js.map +1 -1
- package/dist/languageService/definitionProvider.js +2 -1
- package/dist/languageService/definitionProvider.js.map +1 -1
- package/dist/languageService/documentSymbolProvider.js +2 -1
- package/dist/languageService/documentSymbolProvider.js.map +1 -1
- package/dist/languageService/hoverProvider.js +14 -3
- package/dist/languageService/hoverProvider.js.map +1 -1
- package/dist/languageService/importAdder.d.ts +2 -2
- package/dist/languageService/importAdder.js +5 -3
- package/dist/languageService/importAdder.js.map +1 -1
- package/dist/languageService/indentationUtils.d.ts +6 -2
- package/dist/languageService/indentationUtils.js +33 -13
- package/dist/languageService/indentationUtils.js.map +1 -1
- package/dist/languageService/renameModuleProvider.d.ts +10 -2
- package/dist/languageService/renameModuleProvider.js +87 -14
- package/dist/languageService/renameModuleProvider.js.map +1 -1
- package/dist/localization/localize.d.ts +12 -2
- package/dist/localization/localize.js +5 -1
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.en-us.json +6 -2
- package/dist/parser/parser.js +18 -18
- package/dist/parser/parser.js.map +1 -1
- package/dist/pyright.js +1 -1
- package/dist/pyright.js.map +1 -1
- package/dist/tests/docStringConversion.test.js +23 -0
- package/dist/tests/docStringConversion.test.js.map +1 -1
- package/dist/tests/fourslash/completions.errorNodes.fourslash.d.ts +1 -0
- package/dist/tests/fourslash/completions.errorNodes.fourslash.js +24 -0
- package/dist/tests/fourslash/completions.errorNodes.fourslash.js.map +1 -0
- package/dist/tests/fourslash/hover.docstring.parameter.fourslash.d.ts +1 -0
- package/dist/tests/fourslash/hover.docstring.parameter.fourslash.js +57 -0
- package/dist/tests/fourslash/hover.docstring.parameter.fourslash.js.map +1 -0
- package/dist/tests/fourslash/hover.slots.fourslash.d.ts +1 -0
- package/dist/tests/fourslash/hover.slots.fourslash.js +16 -0
- package/dist/tests/fourslash/hover.slots.fourslash.js.map +1 -0
- package/dist/tests/harness/fourslash/testState.js +9 -2
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/importAdder.test.js +16 -3
- package/dist/tests/importAdder.test.js.map +1 -1
- package/dist/tests/indentationUtils.reindent.test.js +22 -1
- package/dist/tests/indentationUtils.reindent.test.js.map +1 -1
- package/dist/tests/moveSymbol.importAdder.test.js +183 -24
- package/dist/tests/moveSymbol.importAdder.test.js.map +1 -1
- package/dist/tests/moveSymbol.insertion.test.js +137 -2
- package/dist/tests/moveSymbol.insertion.test.js.map +1 -1
- package/dist/tests/moveSymbol.misc.test.js +109 -4
- package/dist/tests/moveSymbol.misc.test.js.map +1 -1
- package/dist/tests/renameModuleTestUtils.d.ts +1 -1
- package/dist/tests/renameModuleTestUtils.js +9 -5
- package/dist/tests/renameModuleTestUtils.js.map +1 -1
- package/dist/tests/testStateUtils.js +2 -2
- package/dist/tests/testStateUtils.js.map +1 -1
- package/dist/tests/textEditUtil.test.js +2 -2
- package/dist/tests/textEditUtil.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +8 -0
- package/dist/tests/typeEvaluator1.test.js.map +1 -1
- package/dist/tests/typeEvaluator2.test.js +13 -1
- package/dist/tests/typeEvaluator2.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +29 -4
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +1 -1
- package/dist/tests/typeEvaluator5.test.js +6 -0
- package/dist/tests/typeEvaluator5.test.js.map +1 -1
- package/dist/tests/workspaceEditUtils.test.js +7 -7
- package/dist/tests/workspaceEditUtils.test.js.map +1 -1
- package/package.json +3 -3
- package/dist/common/textEditUtils.js.map +0 -1
@@ -86,6 +86,7 @@ export declare class Program {
|
|
86
86
|
setPreCheckCallback(preCheckCallback: PreCheckCallback): void;
|
87
87
|
setAllowedThirdPartyImports(importNames: string[]): void;
|
88
88
|
addTrackedFiles(filePaths: string[], isThirdPartyImport?: boolean, isInPyTypedPackage?: boolean): void;
|
89
|
+
addInterimFile(filePath: string): SourceFileInfo;
|
89
90
|
addTrackedFile(filePath: string, isThirdPartyImport?: boolean, isInPyTypedPackage?: boolean): SourceFile;
|
90
91
|
setFileOpened(filePath: string, version: number | null, contents: TextDocumentContentChangeEvent[], options?: OpenFileOptions): void;
|
91
92
|
getChainedFilePath(filePath: string): string | undefined;
|
@@ -95,7 +96,7 @@ export declare class Program {
|
|
95
96
|
markFilesDirty(filePaths: string[], evenIfContentsAreSame: boolean, indexingNeeded?: boolean): void;
|
96
97
|
getFileCount(userFileOnly?: boolean): number;
|
97
98
|
getUserFileCount(): number;
|
98
|
-
|
99
|
+
getUserFiles(): SourceFileInfo[];
|
99
100
|
getOpened(): SourceFileInfo[];
|
100
101
|
getFilesToAnalyzeCount(): number;
|
101
102
|
isCheckingOnlyOpenFiles(): boolean;
|
@@ -105,7 +106,7 @@ export declare class Program {
|
|
105
106
|
getSourceFile(filePath: string): SourceFile | undefined;
|
106
107
|
getBoundSourceFile(filePath: string): SourceFile | undefined;
|
107
108
|
getSourceFileInfo(filePath: string): SourceFileInfo | undefined;
|
108
|
-
getBoundSourceFileInfo(filePath: string): SourceFileInfo | undefined;
|
109
|
+
getBoundSourceFileInfo(filePath: string, content?: string, force?: boolean): SourceFileInfo | undefined;
|
109
110
|
analyze(maxTime?: MaxAnalysisTime, token?: CancellationToken): boolean;
|
110
111
|
analyzeFile(filePath: string, token?: CancellationToken): boolean;
|
111
112
|
indexWorkspace(callback: (path: string, results: IndexResults) => void, token: CancellationToken): number;
|
@@ -150,8 +151,8 @@ export declare class Program {
|
|
150
151
|
renameModule(path: string, newPath: string, token: CancellationToken): FileEditActions | undefined;
|
151
152
|
moveSymbolAtPosition(filePath: string, newFilePath: string, position: Position, options: {
|
152
153
|
importFormat: ImportFormat;
|
153
|
-
}, token
|
154
|
-
|
154
|
+
}, token: CancellationToken): FileEditActions | undefined;
|
155
|
+
clone(): Program;
|
155
156
|
canRenameSymbolAtPosition(filePath: string, position: Position, isDefaultWorkspace: boolean, allowModuleRename: boolean, token: CancellationToken): {
|
156
157
|
range: Range;
|
157
158
|
declarations: Declaration[];
|
package/dist/analyzer/program.js
CHANGED
@@ -36,15 +36,16 @@ const collectionUtils_1 = require("../common/collectionUtils");
|
|
36
36
|
const configOptions_1 = require("../common/configOptions");
|
37
37
|
const console_1 = require("../common/console");
|
38
38
|
const debug_1 = require("../common/debug");
|
39
|
-
const diagnosticSink_1 = require("../common/diagnosticSink");
|
40
39
|
const extensibility_1 = require("../common/extensibility");
|
41
40
|
const logTracker_1 = require("../common/logTracker");
|
42
41
|
const pathUtils_1 = require("../common/pathUtils");
|
43
42
|
const positionUtils_1 = require("../common/positionUtils");
|
44
43
|
const stringUtils_1 = require("../common/stringUtils");
|
45
|
-
const
|
44
|
+
const textEditTracker_1 = require("../common/textEditTracker");
|
46
45
|
const textRange_1 = require("../common/textRange");
|
46
|
+
const textRangeCollection_1 = require("../common/textRangeCollection");
|
47
47
|
const timing_1 = require("../common/timing");
|
48
|
+
const workspaceEditUtils_1 = require("../common/workspaceEditUtils");
|
48
49
|
const autoImporter_1 = require("../languageService/autoImporter");
|
49
50
|
const callHierarchyProvider_1 = require("../languageService/callHierarchyProvider");
|
50
51
|
const completionProvider_1 = require("../languageService/completionProvider");
|
@@ -219,6 +220,15 @@ class Program {
|
|
219
220
|
this.addTrackedFile(filePath, isThirdPartyImport, isInPyTypedPackage);
|
220
221
|
});
|
221
222
|
}
|
223
|
+
addInterimFile(filePath) {
|
224
|
+
// Double check not already there.
|
225
|
+
let fileInfo = this.getSourceFileInfo(filePath);
|
226
|
+
if (!fileInfo) {
|
227
|
+
fileInfo = this._createInterimFileInfo(filePath);
|
228
|
+
this._addToSourceFileListAndMap(fileInfo);
|
229
|
+
}
|
230
|
+
return fileInfo;
|
231
|
+
}
|
222
232
|
addTrackedFile(filePath, isThirdPartyImport = false, isInPyTypedPackage = false) {
|
223
233
|
let sourceFileInfo = this.getSourceFileInfo(filePath);
|
224
234
|
const importName = this._getImportNameForFile(filePath);
|
@@ -280,8 +290,6 @@ class Program {
|
|
280
290
|
sourceFileInfo.diagnosticsVersion = 0;
|
281
291
|
}
|
282
292
|
sourceFileInfo.sourceFile.setClientVersion(version, contents);
|
283
|
-
// Tell any extensions that this source file changed.
|
284
|
-
extensibility_1.Extensions.getProgramExtensions(filePath).forEach((e) => e.sourceFileChanged ? e.sourceFileChanged(sourceFileInfo) : undefined);
|
285
293
|
}
|
286
294
|
getChainedFilePath(filePath) {
|
287
295
|
var _a;
|
@@ -369,8 +377,8 @@ class Program {
|
|
369
377
|
getUserFileCount() {
|
370
378
|
return this._sourceFileList.filter((s) => (0, sourceFileInfoUtils_1.isUserCode)(s)).length;
|
371
379
|
}
|
372
|
-
|
373
|
-
return this._sourceFileList.filter((s) =>
|
380
|
+
getUserFiles() {
|
381
|
+
return this._sourceFileList.filter((s) => (0, sourceFileInfoUtils_1.isUserCode)(s));
|
374
382
|
}
|
375
383
|
getOpened() {
|
376
384
|
return this._sourceFileList.filter((s) => s.isOpenByClient);
|
@@ -422,12 +430,12 @@ class Program {
|
|
422
430
|
getSourceFileInfo(filePath) {
|
423
431
|
return this._sourceFileMap.get((0, pathUtils_1.normalizePathCase)(this._fs, filePath));
|
424
432
|
}
|
425
|
-
getBoundSourceFileInfo(filePath) {
|
433
|
+
getBoundSourceFileInfo(filePath, content, force) {
|
426
434
|
const sourceFileInfo = this.getSourceFileInfo(filePath);
|
427
435
|
if (!sourceFileInfo) {
|
428
436
|
return undefined;
|
429
437
|
}
|
430
|
-
this._bindFile(sourceFileInfo);
|
438
|
+
this._bindFile(sourceFileInfo, content, force);
|
431
439
|
return sourceFileInfo;
|
432
440
|
}
|
433
441
|
// Performs parsing and analysis of any source files in the program
|
@@ -678,8 +686,7 @@ class Program {
|
|
678
686
|
_addShadowedFile(stubFile, shadowImplPath) {
|
679
687
|
let shadowFileInfo = this.getSourceFileInfo(shadowImplPath);
|
680
688
|
if (!shadowFileInfo) {
|
681
|
-
shadowFileInfo = this.
|
682
|
-
this._addToSourceFileListAndMap(shadowFileInfo);
|
689
|
+
shadowFileInfo = this.addInterimFile(shadowImplPath);
|
683
690
|
}
|
684
691
|
if (!shadowFileInfo.shadows.includes(stubFile)) {
|
685
692
|
shadowFileInfo.shadows.push(stubFile);
|
@@ -727,8 +734,8 @@ class Program {
|
|
727
734
|
: undefined);
|
728
735
|
return this._evaluator;
|
729
736
|
}
|
730
|
-
_parseFile(fileToParse, content) {
|
731
|
-
if (!this._isFileNeeded(fileToParse) || !fileToParse.sourceFile.isParseRequired()) {
|
737
|
+
_parseFile(fileToParse, content, force) {
|
738
|
+
if (!force && (!this._isFileNeeded(fileToParse) || !fileToParse.sourceFile.isParseRequired())) {
|
732
739
|
return;
|
733
740
|
}
|
734
741
|
if (fileToParse.sourceFile.parse(this._configOptions, this._importResolver, content)) {
|
@@ -747,12 +754,12 @@ class Program {
|
|
747
754
|
}
|
748
755
|
// Binds the specified file and all of its dependencies, recursively. If
|
749
756
|
// it runs out of time, it returns true. If it completes, it returns false.
|
750
|
-
_bindFile(fileToAnalyze, content) {
|
757
|
+
_bindFile(fileToAnalyze, content, force) {
|
751
758
|
var _a, _b;
|
752
|
-
if (!this._isFileNeeded(fileToAnalyze) || !fileToAnalyze.sourceFile.isBindingRequired()) {
|
759
|
+
if (!force && (!this._isFileNeeded(fileToAnalyze) || !fileToAnalyze.sourceFile.isBindingRequired())) {
|
753
760
|
return;
|
754
761
|
}
|
755
|
-
this._parseFile(fileToAnalyze, content);
|
762
|
+
this._parseFile(fileToAnalyze, content, force);
|
756
763
|
const getScopeIfAvailable = (fileInfo) => {
|
757
764
|
if (!fileInfo || fileInfo === fileToAnalyze) {
|
758
765
|
return undefined;
|
@@ -1376,13 +1383,8 @@ class Program {
|
|
1376
1383
|
});
|
1377
1384
|
}
|
1378
1385
|
moveSymbolAtPosition(filePath, newFilePath, position, options, token) {
|
1379
|
-
if (vscode_languageserver_1.CancellationToken.is(options)) {
|
1380
|
-
return this._moveSymbolAtPosition(filePath, newFilePath, position, { importFormat: "absolute" /* Absolute */ }, options);
|
1381
|
-
}
|
1382
|
-
return this._moveSymbolAtPosition(filePath, newFilePath, position, options, token);
|
1383
|
-
}
|
1384
|
-
_moveSymbolAtPosition(filePath, newFilePath, position, options, token) {
|
1385
1386
|
return this._runEvaluatorWithCancellationToken(token, () => {
|
1387
|
+
var _a, _b;
|
1386
1388
|
const sourceFileExt = (0, pathUtils_1.getFileExtension)(filePath);
|
1387
1389
|
const destFileExt = (0, pathUtils_1.getFileExtension)(newFilePath);
|
1388
1390
|
if (sourceFileExt.toLowerCase() !== destFileExt.toLowerCase()) {
|
@@ -1412,9 +1414,21 @@ class Program {
|
|
1412
1414
|
return undefined;
|
1413
1415
|
}
|
1414
1416
|
// If this isn't a name node, there are no references to be found.
|
1415
|
-
if (node.nodeType !== 38 /* Name */) {
|
1417
|
+
if (node.nodeType !== 38 /* Name */ || !renameModuleProvider_1.RenameModuleProvider.canMoveSymbol(this._evaluator, node)) {
|
1416
1418
|
return undefined;
|
1417
1419
|
}
|
1420
|
+
// We will try to
|
1421
|
+
// 1. Find symbol to move.
|
1422
|
+
// 2. Update all references to the symbol to new location.
|
1423
|
+
// 3. Remove the existing symbol.
|
1424
|
+
// 4. Insert the symbol to the destination module.
|
1425
|
+
// 5. Insert imports required for the symbol moved to the destination module.
|
1426
|
+
// 6. Remove import no longer needed from the original module.
|
1427
|
+
//
|
1428
|
+
// Here all changes are done to edits, no features in LS will apply changes to
|
1429
|
+
// program directly. All modification is done through LSP by a edit request so
|
1430
|
+
// things like undo or edit stacks UI works.
|
1431
|
+
// 1. Find symbol to move.
|
1418
1432
|
const execEnv = this._configOptions.findExecEnvironment(filePath);
|
1419
1433
|
const declarations = documentSymbolCollector_1.DocumentSymbolCollector.getDeclarationsForNode(node, this._evaluator,
|
1420
1434
|
/* resolveLocalNames */ false, documentSymbolCollector_1.DocumentSymbolCollectorUseCase.Rename, token, this._createSourceMapper(execEnv, token, fileInfo));
|
@@ -1422,21 +1436,21 @@ class Program {
|
|
1422
1436
|
if (!renameModuleProvider) {
|
1423
1437
|
return undefined;
|
1424
1438
|
}
|
1439
|
+
// 2. Update affected references.
|
1425
1440
|
this._processModuleReferences(renameModuleProvider, node.value, filePath);
|
1441
|
+
// 3. Remove existing symbols.
|
1426
1442
|
const sourceDecl = renameModuleProvider.declarations.find((d) => d.node && (0, pathUtils_1.getFileExtension)(d.path) === sourceFileExt);
|
1427
1443
|
if (!sourceDecl) {
|
1428
1444
|
// Can't find symbol we can move.
|
1429
1445
|
return undefined;
|
1430
1446
|
}
|
1447
|
+
const symbolRange = renameModuleProvider_1.RenameModuleProvider.getSymbolTextRange(parseResults, sourceDecl);
|
1431
1448
|
const importAdder = new importAdder_1.ImportAdder(this._configOptions, this._importResolver, this._evaluator);
|
1432
|
-
const collectedimports = importAdder.collectImportsForSymbolsUsed(parseResults,
|
1449
|
+
const collectedimports = importAdder.collectImportsForSymbolsUsed(parseResults, symbolRange, token);
|
1433
1450
|
let insertionPoint = 0;
|
1434
1451
|
let insertionIndentation = 0;
|
1435
1452
|
const newFileParseResults = newFileInfo === null || newFileInfo === void 0 ? void 0 : newFileInfo.sourceFile.getParseResults();
|
1436
1453
|
if (newFileParseResults) {
|
1437
|
-
// TODO: Add "insertAfter" option to make sure we insert symbol after that point.
|
1438
|
-
// For example, if collectedImports has symbols from the destination file, we should
|
1439
|
-
// insert after those symbols are defined.
|
1440
1454
|
const insertBefore = renameModuleProvider.tryGetFirstSymbolUsage(newFileParseResults);
|
1441
1455
|
insertionPoint = (0, insertionPointUtils_1.getInsertionPointForSymbolUnderModule)(this._evaluator, newFileParseResults, node.value, {
|
1442
1456
|
symbolDeclToIgnore: sourceDecl.path,
|
@@ -1446,16 +1460,15 @@ class Program {
|
|
1446
1460
|
// No place to insert the symbol.
|
1447
1461
|
return undefined;
|
1448
1462
|
}
|
1449
|
-
insertionIndentation = (0, indentationUtils_1.
|
1463
|
+
insertionIndentation = (0, indentationUtils_1.getModuleStatementIndentation)(newFileParseResults);
|
1450
1464
|
}
|
1465
|
+
const reindentResult = (0, indentationUtils_1.reindentSpan)(parseResults, symbolRange, insertionIndentation);
|
1466
|
+
const fullRange = renameModuleProvider_1.RenameModuleProvider.getSymbolFullStatementTextRange(parseResults, sourceDecl);
|
1467
|
+
renameModuleProvider.textEditTracker.addEdit(filePath, (0, positionUtils_1.convertTextRangeToRange)(textRange_1.TextRange.combine([reindentResult.originalSpan, fullRange]), parseResults.tokenizerOutput.lines), '');
|
1468
|
+
// 4. Add the symbol to the destination file.
|
1451
1469
|
const fileOperations = [];
|
1452
|
-
|
1453
|
-
let codeSnippetToInsert = (0, indentationUtils_1.reindentSpan)(parseResults, sourceDecl.node, insertionIndentation);
|
1470
|
+
let codeSnippetToInsert = reindentResult.text;
|
1454
1471
|
if (newFileParseResults) {
|
1455
|
-
// TODO: We need to "add import" statement for symbols defined in the destination file
|
1456
|
-
// if we couldn't find insertion point where all constraints are met.
|
1457
|
-
// For example, if the symbol we are moving is used before other symbols it references are declared.
|
1458
|
-
importAdder.applyImportsTo(collectedimports, newFileParseResults, options.importFormat, renameModuleProvider.textEditTracker, token);
|
1459
1472
|
const range = (0, positionUtils_1.convertTextRangeToRange)({ start: insertionPoint, length: 0 }, newFileParseResults.tokenizerOutput.lines);
|
1460
1473
|
// If we are adding at the end of line (ex, end of a file),
|
1461
1474
|
// add new lines.
|
@@ -1465,16 +1478,121 @@ class Program {
|
|
1465
1478
|
}
|
1466
1479
|
else {
|
1467
1480
|
fileOperations.push({ kind: 'create', filePath: newFilePath });
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1481
|
+
renameModuleProvider.textEditTracker.addEdit(newFilePath, (0, textRange_1.getEmptyRange)(), codeSnippetToInsert);
|
1482
|
+
}
|
1483
|
+
// 5. Insert imports required for the symbol moved to the destination module.
|
1484
|
+
//
|
1485
|
+
// Since step 5 and 6 can create nested edits, we clone the program and apply all changes to re-calculate
|
1486
|
+
// edits we need to apply to the destination file. The same workflow as `fix all` but done in program level
|
1487
|
+
// not service level.
|
1488
|
+
const cloned = this.clone();
|
1489
|
+
let edits = renameModuleProvider.getEdits();
|
1490
|
+
const textAfterSymbolAdded = (0, workspaceEditUtils_1.applyTextEditsToString)(edits.filter((v) => v.filePath === newFilePath), (_a = newFileParseResults === null || newFileParseResults === void 0 ? void 0 : newFileParseResults.tokenizerOutput.lines) !== null && _a !== void 0 ? _a : new textRangeCollection_1.TextRangeCollection([]), (_b = newFileInfo === null || newFileInfo === void 0 ? void 0 : newFileInfo.sourceFile.getFileContent()) !== null && _b !== void 0 ? _b : '');
|
1491
|
+
_updateFileContent(cloned, newFilePath, textAfterSymbolAdded);
|
1492
|
+
const textAfterImportsAdded = _tryGetTextAfterImportsAdded(cloned, newFilePath, collectedimports, insertionPoint, token);
|
1493
|
+
edits = _updateFileEditActions(edits, newFilePath, newFileParseResults, textAfterSymbolAdded, textAfterImportsAdded);
|
1494
|
+
// 6. Remove imports no longer required from original module.
|
1495
|
+
const textAfterSymbolRemoved = (0, workspaceEditUtils_1.applyTextEditsToString)(edits.filter((v) => v.filePath === filePath), parseResults.tokenizerOutput.lines, fileInfo.sourceFile.getFileContent());
|
1496
|
+
_updateFileContent(cloned, filePath, textAfterSymbolRemoved);
|
1497
|
+
const textAfterUnusedImportsRemoved = _tryGetTextAfterUnusedImportsRemoved(cloned, filePath, collectedimports, 0, token);
|
1498
|
+
edits = _updateFileEditActions(edits, filePath, parseResults, textAfterSymbolRemoved, textAfterUnusedImportsRemoved);
|
1499
|
+
cloned.dispose();
|
1473
1500
|
return {
|
1474
|
-
edits
|
1501
|
+
edits,
|
1475
1502
|
fileOperations,
|
1476
1503
|
};
|
1504
|
+
function _updateFileEditActions(edits, filePath, parseResults, oldText, newText) {
|
1505
|
+
if (newText === undefined || oldText === newText) {
|
1506
|
+
return edits;
|
1507
|
+
}
|
1508
|
+
// There were nested edits. Replace whole file.
|
1509
|
+
edits = edits.filter((v) => v.filePath !== filePath);
|
1510
|
+
edits.push({
|
1511
|
+
filePath,
|
1512
|
+
range: parseResults
|
1513
|
+
? (0, positionUtils_1.convertTextRangeToRange)(parseResults.parseTree, parseResults.tokenizerOutput.lines)
|
1514
|
+
: (0, textRange_1.getEmptyRange)(),
|
1515
|
+
replacementText: newText,
|
1516
|
+
});
|
1517
|
+
return edits;
|
1518
|
+
}
|
1519
|
+
function _tryGetTextAfterImportsAdded(cloned, filePath, importData, insertionPoint, token) {
|
1520
|
+
const sourceFile = cloned.getBoundSourceFile(filePath);
|
1521
|
+
const parseResults = sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.getParseResults();
|
1522
|
+
if (!parseResults) {
|
1523
|
+
return undefined;
|
1524
|
+
}
|
1525
|
+
const insertAddEdits = importAdder.applyImports(importData, filePath, parseResults, insertionPoint, options.importFormat, token);
|
1526
|
+
return (0, workspaceEditUtils_1.applyTextEditsToString)(insertAddEdits, parseResults.tokenizerOutput.lines, sourceFile.getFileContent());
|
1527
|
+
}
|
1528
|
+
function _tryGetTextAfterUnusedImportsRemoved(cloned, filePath, importData, attempt, token) {
|
1529
|
+
var _a;
|
1530
|
+
(0, cancellationUtils_1.throwIfCancellationRequested)(token);
|
1531
|
+
cloned.analyzeFile(filePath, token);
|
1532
|
+
const sourceFile = cloned.getBoundSourceFile(filePath);
|
1533
|
+
const parseResults = sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.getParseResults();
|
1534
|
+
if (!parseResults) {
|
1535
|
+
return undefined;
|
1536
|
+
}
|
1537
|
+
const tracker = new textEditTracker_1.TextEditTracker();
|
1538
|
+
for (const diagnostic of cloned
|
1539
|
+
.getDiagnosticsForRange(filePath, (0, positionUtils_1.convertTextRangeToRange)(parseResults.parseTree, parseResults.tokenizerOutput.lines))
|
1540
|
+
.filter((d) => {
|
1541
|
+
var _a;
|
1542
|
+
return d.category === 3 /* UnusedCode */ &&
|
1543
|
+
((_a = d.getActions()) === null || _a === void 0 ? void 0 : _a.some((a) => a.action === "pyright.unusedImport" /* unusedImport */));
|
1544
|
+
})) {
|
1545
|
+
const nameNode = (0, parseTreeUtils_1.findNodeByPosition)(parseResults.parseTree, diagnostic.range.start, parseResults.tokenizerOutput.lines);
|
1546
|
+
if ((nameNode === null || nameNode === void 0 ? void 0 : nameNode.nodeType) !== 38 /* Name */) {
|
1547
|
+
continue;
|
1548
|
+
}
|
1549
|
+
// decl is synthesized. there is no node associated with the decl.
|
1550
|
+
// ex) import a or import a.b
|
1551
|
+
const dottedName1 = ((_a = nameNode.parent) === null || _a === void 0 ? void 0 : _a.nodeType) === 37 /* ModuleName */ ? nameNode.parent.nameParts : [nameNode];
|
1552
|
+
for (const [decl, names] of importData.declarations) {
|
1553
|
+
if (decl.node) {
|
1554
|
+
if (textRange_1.TextRange.containsRange(decl.node, nameNode)) {
|
1555
|
+
tracker.removeNodes({ node: nameNode, parseResults: parseResults });
|
1556
|
+
break;
|
1557
|
+
}
|
1558
|
+
}
|
1559
|
+
const dottedName2 = (0, parseTreeUtils_1.getDottedName)((0, parseTreeUtils_1.getDottedNameWithGivenNodeAsLastName)(names[0]));
|
1560
|
+
if (dottedName2 && (0, collectionUtils_1.arrayEquals)(dottedName1, dottedName2, (e1, e2) => e1.value === e2.value)) {
|
1561
|
+
tracker.removeNodes({ node: nameNode, parseResults: parseResults });
|
1562
|
+
break;
|
1563
|
+
}
|
1564
|
+
}
|
1565
|
+
}
|
1566
|
+
const oldText = sourceFile.getFileContent();
|
1567
|
+
const newText = (0, workspaceEditUtils_1.applyTextEditsToString)(tracker.getEdits(token).filter((v) => v.filePath === filePath), parseResults.tokenizerOutput.lines, oldText);
|
1568
|
+
// We will attempt to remove unused imports multiple times since removing 1 unused import
|
1569
|
+
// could make another import unused. This is due to how we calculate which import is not used.
|
1570
|
+
// ex) import os, os.path, os.path.xxx
|
1571
|
+
// `os.path` and `os.path.xxx` will be marked as used due to `import os`.
|
1572
|
+
// once `os` is removed `os.path` will be marked as unused and so on.
|
1573
|
+
// We will attempt to remove those chained unused imports up to 10 chain.
|
1574
|
+
if (attempt > 10 || oldText === newText) {
|
1575
|
+
return newText;
|
1576
|
+
}
|
1577
|
+
_updateFileContent(cloned, filePath, newText);
|
1578
|
+
return _tryGetTextAfterUnusedImportsRemoved(cloned, filePath, importData, attempt + 1, token);
|
1579
|
+
}
|
1477
1580
|
});
|
1581
|
+
function _updateFileContent(cloned, filePath, text) {
|
1582
|
+
var _a, _b;
|
1583
|
+
const info = cloned.getSourceFileInfo(filePath);
|
1584
|
+
const version = info ? ((_a = info.sourceFile.getClientVersion()) !== null && _a !== void 0 ? _a : 0) + 1 : 0;
|
1585
|
+
const chainedFilePath = info ? (_b = info.chainedSourceFile) === null || _b === void 0 ? void 0 : _b.sourceFile.getFilePath() : undefined;
|
1586
|
+
const ipythonMode = info ? info.sourceFile.getIPythonMode() : sourceFile_1.IPythonMode.None;
|
1587
|
+
const isTracked = info ? info.isTracked : true;
|
1588
|
+
const realFilePath = info ? info.sourceFile.getRealFilePath() : filePath;
|
1589
|
+
cloned.setFileOpened(filePath, version, [{ text }], {
|
1590
|
+
chainedFilePath,
|
1591
|
+
ipythonMode,
|
1592
|
+
isTracked,
|
1593
|
+
realFilePath,
|
1594
|
+
});
|
1595
|
+
}
|
1478
1596
|
function _getNumberOfBlankLinesToInsert(parseResults, position) {
|
1479
1597
|
// This basically try to add 2 blanks lines before previous line with text.
|
1480
1598
|
if (position.line === 0 && position.character === 0) {
|
@@ -1489,6 +1607,28 @@ class Program {
|
|
1489
1607
|
return position.character !== 0 ? linesToAdd + 1 : linesToAdd;
|
1490
1608
|
}
|
1491
1609
|
}
|
1610
|
+
clone() {
|
1611
|
+
var _a;
|
1612
|
+
const program = new Program(this._importResolver, this._configOptions, this._console, new logTracker_1.LogTracker(this._console, 'Cloned'));
|
1613
|
+
// Cloned program will use whatever user files the program currently has.
|
1614
|
+
const userFiles = this.getUserFiles();
|
1615
|
+
program.setTrackedFiles(userFiles.map((i) => i.sourceFile.getFilePath()));
|
1616
|
+
program.markAllFilesDirty(true);
|
1617
|
+
// Make sure we keep editor content (open file) which could be different than one in the file system.
|
1618
|
+
for (const fileInfo of this.getOpened()) {
|
1619
|
+
const version = fileInfo.sourceFile.getClientVersion();
|
1620
|
+
if (version === undefined) {
|
1621
|
+
continue;
|
1622
|
+
}
|
1623
|
+
program.setFileOpened(fileInfo.sourceFile.getFilePath(), version, [{ text: fileInfo.sourceFile.getOpenFileContents() }], {
|
1624
|
+
chainedFilePath: (_a = fileInfo.chainedSourceFile) === null || _a === void 0 ? void 0 : _a.sourceFile.getFilePath(),
|
1625
|
+
ipythonMode: fileInfo.sourceFile.getIPythonMode(),
|
1626
|
+
isTracked: fileInfo.isTracked,
|
1627
|
+
realFilePath: fileInfo.sourceFile.getRealFilePath(),
|
1628
|
+
});
|
1629
|
+
}
|
1630
|
+
return program;
|
1631
|
+
}
|
1492
1632
|
canRenameSymbolAtPosition(filePath, position, isDefaultWorkspace, allowModuleRename, token) {
|
1493
1633
|
return this._runEvaluatorWithCancellationToken(token, () => {
|
1494
1634
|
const sourceFileInfo = this.getSourceFileInfo(filePath);
|
@@ -1681,6 +1821,7 @@ class Program {
|
|
1681
1821
|
this._createNewEvaluator();
|
1682
1822
|
this._discardCachedParseResults();
|
1683
1823
|
this._parsedFileCount = 0;
|
1824
|
+
extensibility_1.Extensions.getProgramExtensions(this.rootPath).forEach((e) => (e.clearCache ? e.clearCache() : null));
|
1684
1825
|
}
|
1685
1826
|
test_createSourceMapper(execEnv, from) {
|
1686
1827
|
return this._createSourceMapper(execEnv, vscode_languageserver_1.CancellationToken.None, /*from*/ from, /* mapCompiled */ false);
|
@@ -1911,8 +2052,7 @@ class Program {
|
|
1911
2052
|
// Special case for import statement.
|
1912
2053
|
// ex) import X.Y
|
1913
2054
|
// SourceFile for X might not be in memory since import `X.Y` only brings in Y
|
1914
|
-
stubFileInfo = this.
|
1915
|
-
this._addToSourceFileListAndMap(stubFileInfo);
|
2055
|
+
stubFileInfo = this.addInterimFile(stubFilePath);
|
1916
2056
|
}
|
1917
2057
|
this._addShadowedFile(stubFileInfo, implFilePath);
|
1918
2058
|
return this.getBoundSourceFile(implFilePath);
|
@@ -1922,8 +2062,7 @@ class Program {
|
|
1922
2062
|
// Special case for import statement.
|
1923
2063
|
// ex) import X.Y
|
1924
2064
|
// SourceFile for X might not be in memory since import `X.Y` only brings in Y
|
1925
|
-
fileInfo = this.
|
1926
|
-
this._addToSourceFileListAndMap(fileInfo);
|
2065
|
+
fileInfo = this.addInterimFile(f);
|
1927
2066
|
// Even though this file is not referenced by anything, make sure
|
1928
2067
|
// we have parse tree for doc string.
|
1929
2068
|
fileInfo.sourceFile.parse(this._configOptions, this._importResolver);
|