From fc9a595992a440ce0f7ef98f06eaa67f1b1a2715 Mon Sep 17 00:00:00 2001 From: "vs-code-engineering[bot]" <122617954+vs-code-engineering[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 18:28:43 +0000 Subject: [PATCH] fix: drop diagnostics with missing range at the language diagnostics boundary (fixes #323148) (#323153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: drop diagnostics with missing range at the language diagnostics boundary Other extensions can publish vscode.Diagnostic entries whose `range` is undefined (violating the non-nullable `range: Range` type via an `any` cast). These reach copilot verbatim through `vscode.languages.getDiagnostics()` and crash the many consumers that dereference `diagnostic.range` - notably the `LintErrors.getData` telemetry path that scans every extension's diagnostics via `getAllDiagnostics()`. Sanitize at the boundary service so every consumer is protected once, and log dropped entries so the producer stays diagnosable. Fixes microsoft/vscode#323148 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: Copilot - Test lint — use strict equality for range null/undefined check The eqeqeq ESLint rule (configured as 'warn', enforced with --max-warnings=0) flagged `range != null` in _dropMalformedDiagnostics. Replace the loose equality with an explicit strict check that preserves the original semantics of dropping diagnostics whose range is either null or undefined. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: vs-code-engineering[bot] <122617954+vs-code-engineering[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../vscode/languageDiagnosticsServiceImpl.ts | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/extensions/copilot/src/platform/languages/vscode/languageDiagnosticsServiceImpl.ts b/extensions/copilot/src/platform/languages/vscode/languageDiagnosticsServiceImpl.ts index 5af945d1b66..6505f80f3ab 100644 --- a/extensions/copilot/src/platform/languages/vscode/languageDiagnosticsServiceImpl.ts +++ b/extensions/copilot/src/platform/languages/vscode/languageDiagnosticsServiceImpl.ts @@ -4,18 +4,46 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { ILogService } from '../../log/common/logService'; import { AbstractLanguageDiagnosticsService } from '../common/languageDiagnosticsService'; export class LanguageDiagnosticsServiceImpl extends AbstractLanguageDiagnosticsService { private static ignoredSchemes = new Set(['git', 'chat-editing-snapshot-text-model', 'chat-editing-text-model']); override onDidChangeDiagnostics: vscode.Event = vscode.languages.onDidChangeDiagnostics; + constructor( + @ILogService private readonly _logService: ILogService, + ) { + super(); + } + override getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[] { - return vscode.languages.getDiagnostics(resource); + return this._dropMalformedDiagnostics(vscode.languages.getDiagnostics(resource)); } override getAllDiagnostics(): [vscode.Uri, vscode.Diagnostic[]][] { return vscode.languages.getDiagnostics() - .filter(([uri]) => !LanguageDiagnosticsServiceImpl.ignoredSchemes.has(uri.scheme)); + .filter(([uri]) => !LanguageDiagnosticsServiceImpl.ignoredSchemes.has(uri.scheme)) + .map(([uri, diagnostics]): [vscode.Uri, vscode.Diagnostic[]] => [uri, this._dropMalformedDiagnostics(diagnostics)]); + } + + /** + * Diagnostics are produced by arbitrary extensions and reach us verbatim through the + * `vscode.languages.getDiagnostics` API. An extension can publish an entry that violates the + * {@link vscode.Diagnostic} contract at runtime - most notably with a missing `range` assigned + * through an `any` cast - and such an entry crashes the many consumers that dereference + * `diagnostic.range`. Drop the malformed entries here, at the extension boundary, and surface + * the occurrence so the underlying producer stays diagnosable. + */ + private _dropMalformedDiagnostics(diagnostics: vscode.Diagnostic[]): vscode.Diagnostic[] { + const valid = diagnostics.filter(diagnostic => { + const range: vscode.Range | null | undefined = diagnostic.range; + return range !== null && range !== undefined; + }); + const dropped = diagnostics.length - valid.length; + if (dropped > 0) { + this._logService.warn(`[LanguageDiagnosticsService] Ignored ${dropped} diagnostic(s) with a missing range received from the diagnostics API.`); + } + return valid; } }