初始化上传
Some checks failed
Run mypy_primer on push / Run mypy_primer on push (push) Has been cancelled
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
Some checks failed
Run mypy_primer on push / Run mypy_primer on push (push) Has been cancelled
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* BackgroundAnalysisProgram.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Applies operations to both the foreground program and a background
|
||||
* analysis running in a worker process.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver';
|
||||
|
||||
import { IBackgroundAnalysis, RefreshOptions } from '../backgroundAnalysisBase';
|
||||
import { ConfigOptions, ExecutionEnvironment } from '../common/configOptions';
|
||||
import { Diagnostic } from '../common/diagnostic';
|
||||
import { FileDiagnostics } from '../common/diagnosticSink';
|
||||
import { ServiceProvider } from '../common/serviceProvider';
|
||||
import '../common/serviceProviderExtensions';
|
||||
import { Range } from '../common/textRange';
|
||||
import { Uri } from '../common/uri/uri';
|
||||
import { AnalysisCompleteCallback, analyzeProgram } from './analysis';
|
||||
import { ImportResolver } from './importResolver';
|
||||
import { MaxAnalysisTime, OpenFileOptions, Program } from './program';
|
||||
import { TypeStubWriter } from './typeStubWriter';
|
||||
|
||||
export enum InvalidatedReason {
|
||||
Reanalyzed,
|
||||
SourceWatcherChanged,
|
||||
LibraryWatcherChanged,
|
||||
LibraryWatcherContentOnlyChanged,
|
||||
}
|
||||
|
||||
export class BackgroundAnalysisProgram {
|
||||
private _program: Program;
|
||||
private _disposed = false;
|
||||
private _onAnalysisCompletion: AnalysisCompleteCallback | undefined;
|
||||
private _preEditAnalysis: IBackgroundAnalysis | undefined;
|
||||
|
||||
constructor(
|
||||
protected readonly serviceId: string,
|
||||
private readonly _serviceProvider: ServiceProvider,
|
||||
private _configOptions: ConfigOptions,
|
||||
private _importResolver: ImportResolver,
|
||||
private _backgroundAnalysis?: IBackgroundAnalysis,
|
||||
private readonly _maxAnalysisTime?: MaxAnalysisTime,
|
||||
private readonly _disableChecker?: boolean,
|
||||
program?: Program
|
||||
) {
|
||||
this._program =
|
||||
program ??
|
||||
new Program(
|
||||
this.importResolver,
|
||||
this.configOptions,
|
||||
this._serviceProvider,
|
||||
undefined,
|
||||
this._disableChecker,
|
||||
serviceId
|
||||
);
|
||||
this._backgroundAnalysis?.setProgramView(this._program);
|
||||
}
|
||||
|
||||
get serviceProvider() {
|
||||
return this._serviceProvider;
|
||||
}
|
||||
|
||||
get configOptions() {
|
||||
return this._configOptions;
|
||||
}
|
||||
|
||||
get importResolver() {
|
||||
return this._importResolver;
|
||||
}
|
||||
|
||||
get program() {
|
||||
return this._program;
|
||||
}
|
||||
|
||||
get host() {
|
||||
return this._importResolver.host;
|
||||
}
|
||||
|
||||
get backgroundAnalysis() {
|
||||
return this._backgroundAnalysis;
|
||||
}
|
||||
|
||||
hasSourceFile(fileUri: Uri): boolean {
|
||||
return !!this._program.getSourceFile(fileUri);
|
||||
}
|
||||
|
||||
setConfigOptions(configOptions: ConfigOptions) {
|
||||
this._configOptions = configOptions;
|
||||
this._backgroundAnalysis?.setConfigOptions(configOptions);
|
||||
this._program.setConfigOptions(configOptions);
|
||||
}
|
||||
|
||||
setImportResolver(importResolver: ImportResolver) {
|
||||
this._importResolver = importResolver;
|
||||
this._backgroundAnalysis?.setImportResolver(importResolver);
|
||||
|
||||
this._program.setImportResolver(importResolver);
|
||||
this.configOptions.getExecutionEnvironments().forEach((e) => this._ensurePartialStubPackages(e));
|
||||
}
|
||||
|
||||
setTrackedFiles(fileUris: Uri[]) {
|
||||
this._backgroundAnalysis?.setTrackedFiles(fileUris);
|
||||
const diagnostics = this._program.setTrackedFiles(fileUris);
|
||||
this._reportDiagnosticsForRemovedFiles(diagnostics);
|
||||
}
|
||||
|
||||
setAllowedThirdPartyImports(importNames: string[]) {
|
||||
this._backgroundAnalysis?.setAllowedThirdPartyImports(importNames);
|
||||
this._program.setAllowedThirdPartyImports(importNames);
|
||||
}
|
||||
|
||||
setFileOpened(fileUri: Uri, version: number | null, contents: string, options: OpenFileOptions) {
|
||||
this._backgroundAnalysis?.setFileOpened(fileUri, version, contents, options);
|
||||
this._program.setFileOpened(fileUri, version, contents, options);
|
||||
}
|
||||
|
||||
getChainedUri(fileUri: Uri): Uri | undefined {
|
||||
return this._program.getChainedUri(fileUri);
|
||||
}
|
||||
|
||||
updateChainedUri(fileUri: Uri, chainedUri: Uri | undefined) {
|
||||
this._backgroundAnalysis?.updateChainedUri(fileUri, chainedUri);
|
||||
this._program.updateChainedUri(fileUri, chainedUri);
|
||||
}
|
||||
|
||||
updateOpenFileContents(uri: Uri, version: number | null, contents: string, options: OpenFileOptions) {
|
||||
this._backgroundAnalysis?.setFileOpened(uri, version, contents, options);
|
||||
this._program.setFileOpened(uri, version, contents, options);
|
||||
this.markFilesDirty([uri], /* evenIfContentsAreSame */ true);
|
||||
}
|
||||
|
||||
setFileClosed(fileUri: Uri) {
|
||||
this._backgroundAnalysis?.setFileClosed(fileUri);
|
||||
const diagnostics = this._program.setFileClosed(fileUri);
|
||||
this._reportDiagnosticsForRemovedFiles(diagnostics);
|
||||
}
|
||||
|
||||
addInterimFile(fileUri: Uri) {
|
||||
this._backgroundAnalysis?.addInterimFile(fileUri);
|
||||
this._program.addInterimFile(fileUri);
|
||||
}
|
||||
|
||||
markAllFilesDirty(evenIfContentsAreSame: boolean) {
|
||||
this._backgroundAnalysis?.markAllFilesDirty(evenIfContentsAreSame);
|
||||
this._program.markAllFilesDirty(evenIfContentsAreSame);
|
||||
}
|
||||
|
||||
markFilesDirty(fileUris: Uri[], evenIfContentsAreSame: boolean) {
|
||||
this._backgroundAnalysis?.markFilesDirty(fileUris, evenIfContentsAreSame);
|
||||
this._program.markFilesDirty(fileUris, evenIfContentsAreSame);
|
||||
}
|
||||
|
||||
setCompletionCallback(callback?: AnalysisCompleteCallback) {
|
||||
this._onAnalysisCompletion = callback;
|
||||
this._backgroundAnalysis?.setCompletionCallback(callback);
|
||||
}
|
||||
|
||||
startAnalysis(token: CancellationToken): boolean {
|
||||
if (this._backgroundAnalysis) {
|
||||
this._backgroundAnalysis.startAnalysis(token);
|
||||
return false;
|
||||
}
|
||||
|
||||
return analyzeProgram(
|
||||
this._program,
|
||||
this._maxAnalysisTime,
|
||||
this._configOptions,
|
||||
this._onAnalysisCompletion,
|
||||
this._serviceProvider.console(),
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
async analyzeFile(fileUri: Uri, token: CancellationToken): Promise<boolean> {
|
||||
if (this._backgroundAnalysis) {
|
||||
return this._backgroundAnalysis.analyzeFile(fileUri, token);
|
||||
}
|
||||
|
||||
return this._program.analyzeFile(fileUri, token);
|
||||
}
|
||||
|
||||
async analyzeFileAndGetDiagnostics(fileUri: Uri, token: CancellationToken): Promise<Diagnostic[]> {
|
||||
if (this._backgroundAnalysis) {
|
||||
return this._backgroundAnalysis.analyzeFileAndGetDiagnostics(fileUri, token);
|
||||
}
|
||||
|
||||
return this._program.analyzeFileAndGetDiagnostics(fileUri, token);
|
||||
}
|
||||
|
||||
libraryUpdated(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
async getDiagnosticsForRange(fileUri: Uri, range: Range, token: CancellationToken): Promise<Diagnostic[]> {
|
||||
if (this._backgroundAnalysis) {
|
||||
return this._backgroundAnalysis.getDiagnosticsForRange(fileUri, range, token);
|
||||
}
|
||||
|
||||
return this._program.getDiagnosticsForRange(fileUri, range);
|
||||
}
|
||||
|
||||
async writeTypeStub(
|
||||
targetImportUri: Uri,
|
||||
targetIsSingleFile: boolean,
|
||||
stubUri: Uri,
|
||||
token: CancellationToken
|
||||
): Promise<any> {
|
||||
if (this._backgroundAnalysis) {
|
||||
return this._backgroundAnalysis.writeTypeStub(targetImportUri, targetIsSingleFile, stubUri, token);
|
||||
}
|
||||
|
||||
return new TypeStubWriter(this._program).writeTypeStub(
|
||||
{
|
||||
targetImportPath: targetImportUri,
|
||||
targetIsSingleFile,
|
||||
outputPath: stubUri,
|
||||
},
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
invalidateAndForceReanalysis(reason: InvalidatedReason, refreshOptions?: RefreshOptions) {
|
||||
this._backgroundAnalysis?.invalidateAndForceReanalysis(reason);
|
||||
|
||||
// Make sure the import resolver doesn't have invalid
|
||||
// cached entries.
|
||||
this._importResolver.invalidateCache();
|
||||
|
||||
// If we have specific changed file URIs and it's a content-only change, mark only those files dirty.
|
||||
// Otherwise, mark all files with one or more errors dirty.
|
||||
if (
|
||||
refreshOptions?.changedFileUris &&
|
||||
refreshOptions.changedFileUris.size > 0 &&
|
||||
reason === InvalidatedReason.LibraryWatcherContentOnlyChanged
|
||||
) {
|
||||
// Convert UriMap keys to array for markFilesDirty
|
||||
const changedFileUris = Array.from(refreshOptions.changedFileUris.keys());
|
||||
this.markFilesDirty(changedFileUris, /* evenIfContentsAreSame */ true);
|
||||
} else {
|
||||
// Mark all files with one or more errors dirty.
|
||||
this._program.markAllFilesDirty(/* evenIfContentsAreSame */ true);
|
||||
}
|
||||
}
|
||||
|
||||
restart() {
|
||||
this._backgroundAnalysis?.restart();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._disposed = true;
|
||||
this._program.dispose();
|
||||
this._backgroundAnalysis?.shutdown();
|
||||
this._backgroundAnalysis?.dispose();
|
||||
}
|
||||
|
||||
enterEditMode() {
|
||||
// Turn off analysis while in edit mode.
|
||||
this._preEditAnalysis = this._backgroundAnalysis;
|
||||
this._backgroundAnalysis = undefined;
|
||||
|
||||
// Forward this request to the program.
|
||||
this._program.enterEditMode();
|
||||
}
|
||||
|
||||
exitEditMode() {
|
||||
this._backgroundAnalysis = this._preEditAnalysis;
|
||||
this._preEditAnalysis = undefined;
|
||||
return this._program.exitEditMode();
|
||||
}
|
||||
|
||||
private _ensurePartialStubPackages(execEnv: ExecutionEnvironment) {
|
||||
this._backgroundAnalysis?.ensurePartialStubPackages(execEnv.root?.toString());
|
||||
return this._importResolver.ensurePartialStubPackages(execEnv);
|
||||
}
|
||||
|
||||
private _reportDiagnosticsForRemovedFiles(fileDiags: FileDiagnostics[]) {
|
||||
if (fileDiags.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If analysis is running in the foreground process, report any
|
||||
// diagnostics that resulted from the close operation (used to
|
||||
// clear diagnostics that are no longer of interest).
|
||||
if (!this._backgroundAnalysis && this._onAnalysisCompletion) {
|
||||
this._onAnalysisCompletion({
|
||||
diagnostics: fileDiags,
|
||||
filesInProgram: this._program.getFileCount(),
|
||||
requiringAnalysisCount: this._program.getFilesToAnalyzeCount(),
|
||||
checkingOnlyOpenFiles: this._program.isCheckingOnlyOpenFiles(),
|
||||
fatalErrorOccurred: false,
|
||||
configParseErrorOccurred: false,
|
||||
elapsedTime: 0,
|
||||
reason: 'tracking',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type BackgroundAnalysisProgramFactory = (
|
||||
serviceId: string,
|
||||
serviceProvider: ServiceProvider,
|
||||
configOptions: ConfigOptions,
|
||||
importResolver: ImportResolver,
|
||||
backgroundAnalysis?: IBackgroundAnalysis,
|
||||
maxAnalysisTime?: MaxAnalysisTime
|
||||
) => BackgroundAnalysisProgram;
|
||||
Reference in New Issue
Block a user