From 953bdc6228983c081e7b3e6648dd6148c38344f7 Mon Sep 17 00:00:00 2001 From: Aman Date: Sun, 7 Dec 2025 03:30:03 +0530 Subject: [PATCH 1/6] debug: fallback to mark breakpoints verified on stopped/breakpoint events --- src/debugger/logTracker.ts | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/debugger/logTracker.ts b/src/debugger/logTracker.ts index 5b34b9c27..cd9798dec 100644 --- a/src/debugger/logTracker.ts +++ b/src/debugger/logTracker.ts @@ -114,6 +114,8 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { return; } + this.handleBreakpointFallback(debugMessage); + if (debugMessage.event === "exited" && debugMessage.body.exitCode) { this.exitCode = debugMessage.body.exitCode; this.exitHandler?.(debugMessage.body.exitCode); @@ -131,6 +133,102 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { } } + private handleBreakpointFallback(rawMsg: unknown): void { + try { + // Minimal typed view of the event payload we care about. + type FrameLike = { source?: { path?: string }; line?: number }; + type BodyLike = { + exitCode?: number; + category?: string; + output?: string; + reason?: string; + thread?: { frames?: FrameLike[] }; + source?: { path?: string }; + line?: number; + }; + + const msg = rawMsg as { type?: string; event?: string; body?: BodyLike | undefined }; + if (!msg || msg.type !== "event") { + return; + } + + // Case A: stopped event with reason = "breakpoint" + if (msg.event === "stopped" && msg.body?.reason === "breakpoint") { + const frames = msg.body.thread?.frames; + if (!Array.isArray(frames) || frames.length === 0) { + return; + } + + const top = frames[0]; + const sourcePath = top?.source?.path; + const line = top?.line; + if (!sourcePath || typeof line !== "number") { + return; + } + + const bpLine0 = line - 1; // VS Code uses 0-based lines + + const breakpoints = vscode.debug.breakpoints.filter( + b => b instanceof vscode.SourceBreakpoint + ) as vscode.SourceBreakpoint[]; + + for (const bp of breakpoints) { + const loc = bp.location; + if (!loc) { + continue; + } + if (loc.uri.fsPath !== sourcePath) { + continue; + } + if (loc.range.start.line !== bpLine0) { + continue; + } + + // Force a UI refresh so the breakpoint shows as installed. + vscode.debug.removeBreakpoints([bp]); + vscode.debug.addBreakpoints([bp]); + break; + } + return; + } + + // Case B: explicit "breakpoint" event that carries source+line info + if (msg.event === "breakpoint" && msg.body) { + const sourcePath = msg.body.source?.path; + const line = msg.body.line; + if (!sourcePath || typeof line !== "number") { + return; + } + + const bpLine0 = line - 1; + const breakpoints = vscode.debug.breakpoints.filter( + b => b instanceof vscode.SourceBreakpoint + ) as vscode.SourceBreakpoint[]; + + for (const bp of breakpoints) { + const loc = bp.location; + if (!loc) { + continue; + } + if (loc.uri.fsPath !== sourcePath) { + continue; + } + if (loc.range.start.line !== bpLine0) { + continue; + } + + vscode.debug.removeBreakpoints([bp]); + vscode.debug.addBreakpoints([bp]); + break; + } + return; + } + } catch (err) { + // eslint-disable-next-line no-console + console.error("Breakpoint fallback error:", err); + } + } + /** * The debug adapter session is about to be stopped. Delete the session from * the tracker From 71fe19d25fc556ff91275f14df38642d4cd8d518 Mon Sep 17 00:00:00 2001 From: Aman Maurya Date: Mon, 8 Dec 2025 19:53:20 +0530 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: award999 --- src/debugger/logTracker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugger/logTracker.ts b/src/debugger/logTracker.ts index cd9798dec..3ca30830c 100644 --- a/src/debugger/logTracker.ts +++ b/src/debugger/logTracker.ts @@ -133,7 +133,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { } } - private handleBreakpointFallback(rawMsg: unknown): void { + private handleBreakpointEvent(rawMsg: unknown): void { try { // Minimal typed view of the event payload we care about. type FrameLike = { source?: { path?: string }; line?: number }; From a1ceb6e1700b53b261d07dde40ad178aa6dcddba Mon Sep 17 00:00:00 2001 From: Aman Date: Tue, 9 Dec 2025 02:26:38 +0530 Subject: [PATCH 3/6] Use location-based breakpoint filtering, add logger, normalize paths --- package-lock.json | 3 +- package.json | 2 +- src/debugger/logTracker.ts | 71 ++++++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index d616cda65..95ef54977 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2732,7 +2732,8 @@ "version": "1.68.0", "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz", "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@vscode/test-cli": { "version": "0.0.12", diff --git a/package.json b/package.json index 82d46d843..2ec3c7588 100644 --- a/package.json +++ b/package.json @@ -2129,11 +2129,11 @@ "sinon-chai": "^3.7.0", "source-map-support": "^0.5.21", "strip-ansi": "^6.0.1", - "vscode-tmgrammar-test": "^0.1.3", "svgo": "^4.0.0", "tsconfig-paths": "^4.2.0", "tsx": "^4.20.6", "typescript": "^5.9.3", + "vscode-tmgrammar-test": "^0.1.3", "winston": "^3.18.3", "winston-transport": "^4.9.0" }, diff --git a/src/debugger/logTracker.ts b/src/debugger/logTracker.ts index 3ca30830c..42e9aaf69 100644 --- a/src/debugger/logTracker.ts +++ b/src/debugger/logTracker.ts @@ -11,6 +11,7 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +import { DebugProtocol } from "@vscode/debugprotocol"; import * as vscode from "vscode"; import { SwiftLogger } from "../logging/SwiftLogger"; @@ -72,6 +73,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { private exitHandler?: (exitCode: number) => void; private output: string[] = []; private exitCode: number | undefined; + private logger?: SwiftLogger; constructor(public id: string) { LoggingDebugAdapterTracker.debugSessionIdMap[id] = this; @@ -90,6 +92,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { cb(o); } if (loggingDebugAdapter.exitCode) { + loggingDebugAdapter.logger = logger; exitHandler(loggingDebugAdapter.exitCode); } loggingDebugAdapter.output = []; @@ -114,7 +117,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { return; } - this.handleBreakpointFallback(debugMessage); + this.handleBreakpointEvent(debugMessage); if (debugMessage.event === "exited" && debugMessage.body.exitCode) { this.exitCode = debugMessage.body.exitCode; @@ -134,27 +137,50 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { } private handleBreakpointEvent(rawMsg: unknown): void { - try { - // Minimal typed view of the event payload we care about. - type FrameLike = { source?: { path?: string }; line?: number }; - type BodyLike = { - exitCode?: number; - category?: string; - output?: string; - reason?: string; - thread?: { frames?: FrameLike[] }; - source?: { path?: string }; - line?: number; + // Narrow-bodied shapes for just the fields we use (local to this function). + type StoppedBodyLike = { + reason?: string; + thread?: { + frames?: { + source?: { path?: string }; + line?: number; + }[]; }; + }; + + type BreakpointBodyLike = { + source?: { path?: string }; + line?: number; + }; + + try { + const msg = rawMsg as DebugProtocol.ProtocolMessage; + const eventMsg = msg as DebugProtocol.Event; - const msg = rawMsg as { type?: string; event?: string; body?: BodyLike | undefined }; if (!msg || msg.type !== "event") { return; } + const normalizePath = (p: string): string => { + try { + // If adapter sends a URI-like path, parse it + if (p.startsWith("file://") || p.includes("://")) { + return vscode.Uri.parse(p).fsPath; + } + // Otherwise treat as filesystem path + return vscode.Uri.file(p).fsPath; + } catch { + // Fallback: return raw + return p; + } + }; + // Case A: stopped event with reason = "breakpoint" - if (msg.event === "stopped" && msg.body?.reason === "breakpoint") { - const frames = msg.body.thread?.frames; + if ( + eventMsg.event === "stopped" && + (eventMsg.body as StoppedBodyLike)?.reason === "breakpoint" + ) { + const frames = (eventMsg.body as StoppedBodyLike)?.thread?.frames; if (!Array.isArray(frames) || frames.length === 0) { return; } @@ -169,7 +195,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { const bpLine0 = line - 1; // VS Code uses 0-based lines const breakpoints = vscode.debug.breakpoints.filter( - b => b instanceof vscode.SourceBreakpoint + b => !!(b as vscode.SourceBreakpoint).location ) as vscode.SourceBreakpoint[]; for (const bp of breakpoints) { @@ -177,7 +203,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { if (!loc) { continue; } - if (loc.uri.fsPath !== sourcePath) { + if (loc.uri.fsPath !== normalizePath(sourcePath)) { continue; } if (loc.range.start.line !== bpLine0) { @@ -193,9 +219,10 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { } // Case B: explicit "breakpoint" event that carries source+line info - if (msg.event === "breakpoint" && msg.body) { - const sourcePath = msg.body.source?.path; - const line = msg.body.line; + if (eventMsg.event === "breakpoint" && eventMsg.body) { + const body = eventMsg.body as BreakpointBodyLike; + const sourcePath = body.source?.path; + const line = body.line; if (!sourcePath || typeof line !== "number") { return; } @@ -210,7 +237,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { if (!loc) { continue; } - if (loc.uri.fsPath !== sourcePath) { + if (loc.uri.fsPath !== normalizePath(sourcePath)) { continue; } if (loc.range.start.line !== bpLine0) { @@ -225,7 +252,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { } } catch (err) { // eslint-disable-next-line no-console - console.error("Breakpoint fallback error:", err); + this.logger?.error(`Breakpoint fallback error: ${String(err)}`); } } From 986a683cbfea643d26eb64d97d8b4d81f2874022 Mon Sep 17 00:00:00 2001 From: Aman Date: Tue, 9 Dec 2025 03:01:43 +0530 Subject: [PATCH 4/6] Changelog: normalize adapter source.path for breakpoint fallback --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f352081f..56b7a53e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### Fixed +- Fix breakpoint filtering fallback in debugger logging ([#1989](https://github.com/swiftlang/vscode-swift/pull/1989)) + +### Fixed + - Fix extension failing to activate when Swiftly was installed via Homebrew ([#1975](https://github.com/swiftlang/vscode-swift/pull/1975)) - Fix running `swift package` commands with `swift.disableSwiftPMIntegration` enabled ([#1969](https://github.com/swiftlang/vscode-swift/pull/1969)) - Fixed an issue where `lldb-dap` could not be found in Command Line Tools toolchains ([#1936](https://github.com/swiftlang/vscode-swift/pull/1936)) From 4079504f5a0ca8a2d3825f9bc60e9f71b1a1bbbd Mon Sep 17 00:00:00 2001 From: Aman Maurya Date: Tue, 9 Dec 2025 03:33:56 +0530 Subject: [PATCH 5/6] Remove duplicate vscode-tmgrammar-test dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ec3c7588..82d46d843 100644 --- a/package.json +++ b/package.json @@ -2129,11 +2129,11 @@ "sinon-chai": "^3.7.0", "source-map-support": "^0.5.21", "strip-ansi": "^6.0.1", + "vscode-tmgrammar-test": "^0.1.3", "svgo": "^4.0.0", "tsconfig-paths": "^4.2.0", "tsx": "^4.20.6", "typescript": "^5.9.3", - "vscode-tmgrammar-test": "^0.1.3", "winston": "^3.18.3", "winston-transport": "^4.9.0" }, From 42a6748d4d12a3d415169e8ba034fc3e7e4b0fbb Mon Sep 17 00:00:00 2001 From: Aman Maurya Date: Tue, 9 Dec 2025 03:38:23 +0530 Subject: [PATCH 6/6] Remove duplicate license entry in package-lock.json --- package-lock.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95ef54977..d616cda65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2732,8 +2732,7 @@ "version": "1.68.0", "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz", "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@vscode/test-cli": { "version": "0.0.12",