Skip to content

Commit de2d23d

Browse files
authored
Improved startup performance for large projects by lazily computing the module name of each source file. (#10798)
1 parent 78088b4 commit de2d23d

5 files changed

Lines changed: 29 additions & 24 deletions

File tree

packages/pyright-internal/src/analyzer/program.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -336,21 +336,19 @@ export class Program {
336336

337337
addTrackedFile(fileUri: Uri, isThirdPartyImport = false, isInPyTypedPackage = false): SourceFile {
338338
let sourceFileInfo = this.getSourceFileInfo(fileUri);
339-
const moduleImportInfo = this._getModuleImportInfoForFile(fileUri);
340-
const importName = moduleImportInfo.moduleName;
341339

342340
if (sourceFileInfo) {
343341
// The module name may have changed based on updates to the
344-
// search paths, so update it here.
345-
sourceFileInfo.sourceFile.setModuleName(importName);
342+
// search paths. Clear any cached module name so it is recomputed.
343+
sourceFileInfo.sourceFile.clearCachedModuleName();
346344
sourceFileInfo.isTracked = true;
347345
return sourceFileInfo.sourceFile;
348346
}
349347

350348
const sourceFile = this._sourceFileFactory.createSourceFile(
351349
this.serviceProvider,
352350
fileUri,
353-
importName,
351+
(uri) => this._getModuleName(uri),
354352
isThirdPartyImport,
355353
isInPyTypedPackage,
356354
this._editModeTracker,
@@ -378,7 +376,7 @@ export class Program {
378376
const sourceFile = this._sourceFileFactory.createSourceFile(
379377
this.serviceProvider,
380378
fileUri,
381-
moduleImportInfo.moduleName,
379+
(uri) => this._getModuleName(uri),
382380
/* isThirdPartyImport */ false,
383381
moduleImportInfo.isThirdPartyPyTypedPresent,
384382
this._editModeTracker,
@@ -1506,11 +1504,10 @@ export class Program {
15061504
// of the program.
15071505
let importedFileInfo = this.getSourceFileInfo(importInfo.path);
15081506
if (!importedFileInfo) {
1509-
const moduleImportInfo = this._getModuleImportInfoForFile(importInfo.path);
15101507
const sourceFile = this._sourceFileFactory.createSourceFile(
15111508
this.serviceProvider,
15121509
importInfo.path,
1513-
moduleImportInfo.moduleName,
1510+
(uri) => this._getModuleName(uri),
15141511
importInfo.isThirdPartyImport,
15151512
importInfo.isPyTypedPresent,
15161513
this._editModeTracker,
@@ -1582,6 +1579,11 @@ export class Program {
15821579
this._sourceFileMap.set(fileUri.key, fileInfo);
15831580
}
15841581

1582+
private _getModuleName(fileUri: Uri): string {
1583+
const moduleInfo = this._getModuleImportInfoForFile(fileUri);
1584+
return moduleInfo.moduleName;
1585+
}
1586+
15851587
private _getModuleImportInfoForFile(fileUri: Uri) {
15861588
// We allow illegal module names (e.g. names that include "-" in them)
15871589
// because we want a unique name for each module even if it cannot be
@@ -1622,11 +1624,10 @@ export class Program {
16221624
}
16231625

16241626
private _createInterimFileInfo(fileUri: Uri) {
1625-
const moduleImportInfo = this._getModuleImportInfoForFile(fileUri);
16261627
const sourceFile = this._sourceFileFactory.createSourceFile(
16271628
this.serviceProvider,
16281629
fileUri,
1629-
moduleImportInfo.moduleName,
1630+
(uri) => this._getModuleName(uri),
16301631
/* isThirdPartyImport */ false,
16311632
/* isInPyTypedPackage */ false,
16321633
this._editModeTracker,

packages/pyright-internal/src/analyzer/programTypes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import { ConsoleInterface } from '../common/console';
99
import { LogTracker } from '../common/logTracker';
1010
import { ServiceProvider } from '../common/serviceProvider';
1111
import { Uri } from '../common/uri/uri';
12-
import { SourceFileEditMode, IPythonMode, SourceFile } from './sourceFile';
12+
import { IPythonMode, SourceFile, SourceFileEditMode } from './sourceFile';
1313

1414
export interface ISourceFileFactory {
1515
createSourceFile(
1616
serviceProvider: ServiceProvider,
1717
fileUri: Uri,
18-
moduleName: string,
18+
moduleNameGetter: (file: Uri) => string,
1919
isThirdPartyImport: boolean,
2020
isThirdPartyPyTypedPresent: boolean,
2121
editMode: SourceFileEditMode,

packages/pyright-internal/src/analyzer/sourceFile.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,11 @@ export class SourceFile {
206206
// identify this file.
207207
private readonly _fileId: string;
208208

209+
// Getter to lazily compute the module name from the file URI.
210+
private _moduleNameGetter: (file: Uri) => string;
211+
209212
// Period-delimited import path for the module.
210-
private _moduleName: string;
213+
private _cachedModuleName: string | undefined;
211214

212215
// True if file is a type-hint (.pyi) file versus a python
213216
// (.py) file.
@@ -257,7 +260,7 @@ export class SourceFile {
257260
constructor(
258261
readonly serviceProvider: ServiceProvider,
259262
uri: Uri,
260-
moduleName: string,
263+
moduleNameGetter: (file: Uri) => string,
261264
isThirdPartyImport: boolean,
262265
isThirdPartyPyTypedPresent: boolean,
263266
editMode: SourceFileEditMode,
@@ -272,7 +275,7 @@ export class SourceFile {
272275
this._editMode = editMode;
273276
this._uri = uri;
274277
this._fileId = this._makeFileId(uri);
275-
this._moduleName = moduleName;
278+
this._moduleNameGetter = moduleNameGetter;
276279
this._isStubFile = uri.hasExtension('.pyi');
277280
this._isThirdPartyImport = isThirdPartyImport;
278281
this._isThirdPartyPyTypedPresent = isThirdPartyPyTypedPresent;
@@ -319,16 +322,17 @@ export class SourceFile {
319322
}
320323

321324
getModuleName(): string {
322-
if (this._moduleName) {
323-
return this._moduleName;
325+
if (!this._cachedModuleName) {
326+
// Call the module name getter. If it returns '' (which can happen if the file is not part
327+
// of the project), fall back to the file name.)
328+
return this._moduleNameGetter(this._uri) || stripFileExtension(this._uri.fileName);
324329
}
325330

326-
// Synthesize a module name using the file path.
327-
return stripFileExtension(this._uri.fileName);
331+
return this._cachedModuleName;
328332
}
329333

330-
setModuleName(name: string) {
331-
this._moduleName = name;
334+
clearCachedModuleName() {
335+
this._cachedModuleName = undefined;
332336
}
333337

334338
getDiagnosticVersion(): number {

packages/pyright-internal/src/common/serviceProviderExtensions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ const DefaultSourceFileFactory: ISourceFileFactory = {
115115
createSourceFile(
116116
serviceProvider: ServiceProvider,
117117
fileUri: Uri,
118-
moduleName: string,
118+
moduleNameGetter: (file: Uri) => string,
119119
isThirdPartyImport: boolean,
120120
isThirdPartyPyTypedPresent: boolean,
121121
editMode: SourceFileEditMode,
@@ -126,7 +126,7 @@ const DefaultSourceFileFactory: ISourceFileFactory = {
126126
return new SourceFile(
127127
serviceProvider,
128128
fileUri,
129-
moduleName,
129+
moduleNameGetter,
130130
isThirdPartyImport,
131131
isThirdPartyPyTypedPresent,
132132
editMode,

packages/pyright-internal/src/tests/sourceFile.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ test('Empty', () => {
2323
const tempFile = new RealTempFile();
2424
const fs = createFromRealFileSystem(tempFile);
2525
const serviceProvider = createServiceProvider(tempFile, fs);
26-
const sourceFile = new SourceFile(serviceProvider, Uri.file(filePath, serviceProvider), '', false, false, {
26+
const sourceFile = new SourceFile(serviceProvider, Uri.file(filePath, serviceProvider), () => '', false, false, {
2727
isEditMode: false,
2828
});
2929
const configOptions = new ConfigOptions(Uri.file(process.cwd(), serviceProvider));

0 commit comments

Comments
 (0)