This commit is contained in:
Colen Garoutte-Carson 2024-09-18 11:35:00 -07:00 коммит произвёл GitHub
Родитель 970f95bfea
Коммит 458ef304e8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 51 добавлений и 94 удалений

Просмотреть файл

@ -246,15 +246,6 @@ interface CompileCommandsPaths extends WorkspaceFolderParams {
paths: string[];
}
interface QueryTranslationUnitSourceParams extends WorkspaceFolderParams {
uri: string;
ignoreExisting: boolean;
}
interface QueryTranslationUnitSourceResult {
candidates: string[];
}
interface GetDiagnosticsResult {
diagnostics: string;
}
@ -554,7 +545,6 @@ export interface ChatContextResult {
const PreInitializationRequest: RequestType<void, string, void> = new RequestType<void, string, void>('cpptools/preinitialize');
const InitializationRequest: RequestType<CppInitializationParams, void, void> = new RequestType<CppInitializationParams, void, void>('cpptools/initialize');
const QueryCompilerDefaultsRequest: RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void> = new RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void>('cpptools/queryCompilerDefaults');
const QueryTranslationUnitSourceRequest: RequestType<QueryTranslationUnitSourceParams, QueryTranslationUnitSourceResult, void> = new RequestType<QueryTranslationUnitSourceParams, QueryTranslationUnitSourceResult, void>('cpptools/queryTranslationUnitSource');
const SwitchHeaderSourceRequest: RequestType<SwitchHeaderSourceParams, string, void> = new RequestType<SwitchHeaderSourceParams, string, void>('cpptools/didSwitchHeaderSource');
const GetDiagnosticsRequest: RequestType<void, GetDiagnosticsResult, void> = new RequestType<void, GetDiagnosticsResult, void>('cpptools/getDiagnostics');
export const GetDocumentSymbolRequest: RequestType<GetDocumentSymbolRequestParams, GetDocumentSymbolResult, void> = new RequestType<GetDocumentSymbolRequestParams, GetDocumentSymbolResult, void>('cpptools/getDocumentSymbols');
@ -744,7 +734,7 @@ export interface Client {
onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable<void>;
updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable<void>;
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void>;
provideCustomConfiguration(docUri: vscode.Uri, requestFile?: string, replaceExisting?: boolean): Promise<void>;
provideCustomConfiguration(docUri: vscode.Uri): Promise<void>;
logDiagnostics(): Promise<void>;
rescanFolder(): Promise<void>;
toggleReferenceResultsView(): void;
@ -1871,9 +1861,6 @@ export class DefaultClient implements Client {
}
await this.clearCustomConfigurations();
await Promise.all([
...[...this.trackedDocuments].map(([_uri, document]) => this.provideCustomConfiguration(document.uri, undefined, true))
]);
}
public async updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Promise<void> {
@ -2023,68 +2010,42 @@ export class DefaultClient implements Client {
return this.languageClient.sendNotification(RescanFolderNotification);
}
public async provideCustomConfiguration(docUri: vscode.Uri, requestFile?: string, replaceExisting?: boolean): Promise<void> {
public async provideCustomConfiguration(docUri: vscode.Uri): Promise<void> {
const onFinished: () => void = () => {
if (requestFile) {
void this.languageClient.sendNotification(FinishedRequestCustomConfig, { uri: requestFile });
}
void this.languageClient.sendNotification(FinishedRequestCustomConfig, { uri: docUri.toString() });
};
const providerId: string | undefined = this.configurationProvider;
if (!providerId) {
onFinished();
return;
}
const provider: CustomConfigurationProvider1 | undefined = getCustomConfigProviders().get(providerId);
if (!provider || !provider.isReady) {
onFinished();
return;
}
try {
DefaultClient.isStarted.reset();
const resultCode = await this.provideCustomConfigurationAsync(docUri, requestFile, replaceExisting, provider);
const providerId: string | undefined = this.configurationProvider;
if (!providerId) {
return;
}
const provider: CustomConfigurationProvider1 | undefined = getCustomConfigProviders().get(providerId);
if (!provider || !provider.isReady) {
return;
}
const resultCode = await this.provideCustomConfigurationAsync(docUri, provider);
telemetry.logLanguageServerEvent('provideCustomConfiguration', { providerId, resultCode });
} finally {
onFinished();
DefaultClient.isStarted.resolve();
}
}
private async provideCustomConfigurationAsync(docUri: vscode.Uri, requestFile: string | undefined, replaceExisting: boolean | undefined, provider: CustomConfigurationProvider1): Promise<string> {
private async provideCustomConfigurationAsync(docUri: vscode.Uri, provider: CustomConfigurationProvider1): Promise<string> {
const tokenSource: vscode.CancellationTokenSource = new vscode.CancellationTokenSource();
const params: QueryTranslationUnitSourceParams = {
uri: docUri.toString(),
ignoreExisting: !!replaceExisting,
workspaceFolderUri: this.RootUri?.toString()
};
const response: QueryTranslationUnitSourceResult = await this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params);
if (!response.candidates || response.candidates.length === 0) {
// If we didn't receive any candidates, no configuration is needed.
return "noCandidates";
}
// Need to loop through candidates, to see if we can get a custom configuration from any of them.
// Wrap all lookups in a single task, so we can apply a timeout to the entire duration.
const provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[] | undefined> = async () => {
const uris: vscode.Uri[] = [];
for (let i: number = 0; i < response.candidates.length; ++i) {
const candidate: string = response.candidates[i];
const tuUri: vscode.Uri = vscode.Uri.parse(candidate);
try {
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
uris.push(tuUri);
}
} catch (err) {
console.warn("Caught exception from canProvideConfiguration");
try {
if (!await provider.canProvideConfiguration(docUri, tokenSource.token)) {
return [];
}
}
if (!uris.length) {
return [];
} catch (err) {
console.warn("Caught exception from canProvideConfiguration");
}
let configs: util.Mutable<SourceFileConfigurationItem>[] = [];
try {
configs = await provider.provideConfigurations(uris, tokenSource.token);
configs = await provider.provideConfigurations([docUri], tokenSource.token);
} catch (err) {
console.warn("Caught exception from provideConfigurations");
}
@ -2132,39 +2093,42 @@ export class DefaultClient implements Client {
try {
const configs: SourceFileConfigurationItem[] | undefined = await this.callTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource);
if (configs && configs.length > 0) {
this.sendCustomConfigurations(configs, provider.version, requestFile !== undefined);
this.sendCustomConfigurations(configs, provider.version);
} else {
result = "noConfigurations";
}
} catch (err) {
result = "timeout";
if (!requestFile) {
const settings: CppSettings = new CppSettings(this.RootUri);
if (settings.isConfigurationWarningsEnabled && !this.isExternalHeader(docUri) && !vscode.debug.activeDebugSession) {
const dismiss: string = localize("dismiss.button", "Dismiss");
const disable: string = localize("disable.warnings.button", "Disable Warnings");
const configName: string | undefined = this.configuration.CurrentConfiguration?.name;
if (!configName) {
return "noConfigName";
}
let message: string = localize("unable.to.provide.configuration",
"{0} is unable to provide IntelliSense configuration information for '{1}'. Settings from the '{2}' configuration will be used instead.",
provider.name, docUri.fsPath, configName);
if (err) {
message += ` (${err})`;
}
const settings: CppSettings = new CppSettings(this.RootUri);
if (settings.isConfigurationWarningsEnabled && !this.isExternalHeader(docUri) && !vscode.debug.activeDebugSession) {
const dismiss: string = localize("dismiss.button", "Dismiss");
const disable: string = localize("disable.warnings.button", "Disable Warnings");
const configName: string | undefined = this.configuration.CurrentConfiguration?.name;
if (!configName) {
return "noConfigName";
}
let message: string = localize("unable.to.provide.configuration",
"{0} is unable to provide IntelliSense configuration information for '{1}'. Settings from the '{2}' configuration will be used instead.",
provider.name, docUri.fsPath, configName);
if (err) {
message += ` (${err})`;
}
if (await vscode.window.showInformationMessage(message, dismiss, disable) === disable) {
settings.toggleSetting("configurationWarnings", "enabled", "disabled");
}
if (await vscode.window.showInformationMessage(message, dismiss, disable) === disable) {
settings.toggleSetting("configurationWarnings", "enabled", "disabled");
}
}
}
return result;
}
private async handleRequestCustomConfig(requestFile: string): Promise<void> {
await this.provideCustomConfiguration(vscode.Uri.file(requestFile), requestFile);
private handleRequestCustomConfig(file: string): void {
const uri: vscode.Uri = vscode.Uri.file(file);
const client: Client = clients.getClientFor(uri);
if (client instanceof DefaultClient) {
const defaultClient: DefaultClient = client as DefaultClient;
void defaultClient.provideCustomConfiguration(uri).catch(logAndReturn.undefined);
}
}
private isExternalHeader(uri: vscode.Uri): boolean {
@ -2386,13 +2350,7 @@ export class DefaultClient implements Client {
this.languageClient.onNotification(CompileCommandsPathsNotification, (e) => void this.promptCompileCommands(e));
this.languageClient.onNotification(ReferencesNotification, (e) => this.processReferencesPreview(e));
this.languageClient.onNotification(ReportReferencesProgressNotification, (e) => this.handleReferencesProgress(e));
this.languageClient.onNotification(RequestCustomConfig, (requestFile: string) => {
const client: Client = clients.getClientFor(vscode.Uri.file(requestFile));
if (client instanceof DefaultClient) {
const defaultClient: DefaultClient = client as DefaultClient;
void defaultClient.handleRequestCustomConfig(requestFile);
}
});
this.languageClient.onNotification(RequestCustomConfig, (e) => this.handleRequestCustomConfig(e));
this.languageClient.onNotification(IntelliSenseResultNotification, (e) => this.handleIntelliSenseResult(e));
this.languageClient.onNotification(PublishRefactorDiagnosticsNotification, publishRefactorDiagnostics);
RegisterCodeAnalysisNotifications(this.languageClient);
@ -3078,7 +3036,7 @@ export class DefaultClient implements Client {
util.isOptionalArrayOfString(input.configuration.forcedInclude);
}
private sendCustomConfigurations(configs: any, providerVersion: Version, wasRequested: boolean): void {
private sendCustomConfigurations(configs: any, providerVersion: Version): void {
// configs is marked as 'any' because it is untrusted data coming from a 3rd-party. We need to sanitize it before sending it to the language server.
if (!configs || !(configs instanceof Array)) {
console.warn("discarding invalid SourceFileConfigurationItems[]: " + configs);
@ -3144,9 +3102,10 @@ export class DefaultClient implements Client {
workspaceFolderUri: this.RootUri?.toString()
};
if (wasRequested) {
void this.languageClient.sendNotification(CustomConfigurationHighPriorityNotification, params).catch(logAndReturn.undefined);
}
// We send the higher priority notification to ensure we don't deadlock if the request is blocking the queue.
// We send the normal priority notification to avoid a race that could result in a redundant request when racing with
// the reset of custom configurations.
void this.languageClient.sendNotification(CustomConfigurationHighPriorityNotification, params).catch(logAndReturn.undefined);
void this.languageClient.sendNotification(CustomConfigurationNotification, params).catch(logAndReturn.undefined);
}
@ -4092,7 +4051,7 @@ class NullClient implements Client {
onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
provideCustomConfiguration(docUri: vscode.Uri, requestFile?: string, replaceExisting?: boolean): Promise<void> { return Promise.resolve(); }
provideCustomConfiguration(docUri: vscode.Uri): Promise<void> { return Promise.resolve(); }
logDiagnostics(): Promise<void> { return Promise.resolve(); }
rescanFolder(): Promise<void> { return Promise.resolve(); }
toggleReferenceResultsView(): void { }

Просмотреть файл

@ -43,7 +43,6 @@ export function createProtocolFilter(): Middleware {
client.sendDidChangeSettings();
document = await vscode.languages.setTextDocumentLanguage(document, "cpp");
}
await client.provideCustomConfiguration(document.uri, undefined);
// client.takeOwnership() will call client.TrackedDocuments.add() again, but that's ok. It's a Set.
client.onDidOpenTextDocument(document);
client.takeOwnership(document);
@ -52,8 +51,7 @@ export function createProtocolFilter(): Middleware {
// For a file already open when we activate, sometimes we don't get any notifications about visible
// or active text editors, visible ranges, or text selection. As a workaround, we trigger
// onDidChangeVisibleTextEditors here, only for the first file opened.
if (!anyFileOpened)
{
if (!anyFileOpened) {
anyFileOpened = true;
const cppEditors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => util.isCpp(e.document));
await client.onDidChangeVisibleTextEditors(cppEditors);