diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts index 3ac4cbba82245..45e8b381fea21 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts @@ -104,21 +104,48 @@ suite('vscode API - debug', function () { assert.strictEqual(addressDbp.accessType, 'readWrite'); }); - test('data breakpoint - dynamic variable', async function () { - debug.addBreakpoints([new DataBreakpoint({ type: 'dynamicVariable', name: 'i', variablesReference: 1000 }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]); + test('data breakpoint - expression', async function () { + debug.addBreakpoints([new DataBreakpoint({ type: 'expression', expression: 'i' }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]); const dynamicVariableDbp = debug.breakpoints[debug.breakpoints.length - 1] as DataBreakpoint; assert.strictEqual(dynamicVariableDbp.condition, 'condition'); assert.strictEqual(dynamicVariableDbp.hitCondition, 'hitCondition'); assert.strictEqual(dynamicVariableDbp.logMessage, 'logMessage'); assert.strictEqual(dynamicVariableDbp.enabled, false); assert.strictEqual(dynamicVariableDbp.label, 'data'); - assert.strictEqual(dynamicVariableDbp.source.type, 'dynamicVariable'); - assert.strictEqual(dynamicVariableDbp.source.name, 'i'); - assert.strictEqual(dynamicVariableDbp.source.variablesReference, 1000); + assert.strictEqual(dynamicVariableDbp.source.type, 'expression'); + assert.strictEqual(dynamicVariableDbp.source.expression, 'i'); assert.strictEqual(dynamicVariableDbp.canPersist, false); assert.strictEqual(dynamicVariableDbp.accessType, 'readWrite'); }); + test('data breakpoint - scoped', async function () { + debug.addBreakpoints([new DataBreakpoint({ type: 'scoped', expression: 'exp()', frameId: 1 }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]); + const scopedExpression = debug.breakpoints[debug.breakpoints.length - 1] as DataBreakpoint; + assert.strictEqual(scopedExpression.condition, 'condition'); + assert.strictEqual(scopedExpression.hitCondition, 'hitCondition'); + assert.strictEqual(scopedExpression.logMessage, 'logMessage'); + assert.strictEqual(scopedExpression.enabled, false); + assert.strictEqual(scopedExpression.label, 'data'); + assert.strictEqual(scopedExpression.source.type, 'scoped'); + assert.strictEqual(scopedExpression.source.frameId, 1); + assert.strictEqual(scopedExpression.source.expression, 'exp()'); + assert.strictEqual(scopedExpression.canPersist, false); + assert.strictEqual(scopedExpression.accessType, 'readWrite'); + + debug.addBreakpoints([new DataBreakpoint({ type: 'scoped', variable: 'var', variablesReference: 1 }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]); + const scopedVariable = debug.breakpoints[debug.breakpoints.length - 1] as DataBreakpoint; + assert.strictEqual(scopedVariable.condition, 'condition'); + assert.strictEqual(scopedVariable.hitCondition, 'hitCondition'); + assert.strictEqual(scopedVariable.logMessage, 'logMessage'); + assert.strictEqual(scopedVariable.enabled, false); + assert.strictEqual(scopedVariable.label, 'data'); + assert.strictEqual(scopedVariable.source.type, 'scoped'); + assert.strictEqual(scopedVariable.source.variablesReference, 1); + assert.strictEqual(scopedVariable.source.variable, 'var'); + assert.strictEqual(scopedVariable.canPersist, false); + assert.strictEqual(scopedVariable.accessType, 'readWrite'); + }); + test('start debugging', async function () { let stoppedEvents = 0; let variablesReceived: () => void; diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 362b4298cdda1..f51de44e2c21a 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -154,6 +154,9 @@ const _allApiProposals = { customEditorMove: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts', }, + debugDataBreakpoints: { + proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugDataBreakpoints.d.ts', + }, debugVisualization: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugVisualization.d.ts', }, diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index e827ccb8a6fc9..fd763dc9f999e 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -8,8 +8,7 @@ import { URI as uri, UriComponents } from '../../../base/common/uri.js'; import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDataBreakpoint, IDebugSessionOptions, IInstructionBreakpoint, DebugConfigurationProviderTriggerKind, IDebugVisualization, DataBreakpointSetType } from '../../contrib/debug/common/debug.js'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, - IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto, IDataBreakpointDto, IStartDebuggingOptions, IDebugConfiguration, IThreadFocusDto, IStackFrameFocusDto, - IDataBreakpointInfo + IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto, IDataBreakpointDto, IStartDebuggingOptions, IDebugConfiguration, IThreadFocusDto, IStackFrameFocusDto } from '../common/extHost.protocol.js'; import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js'; import severity from '../../../base/common/severity.js'; @@ -236,8 +235,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this.debugService.addDataBreakpoint({ description: dto.label, src: dto.source.type === 'variable' ? { type: DataBreakpointSetType.Variable, dataId: dto.source.dataId } - : dto.source.type === 'dynamicVariable' ? { type: DataBreakpointSetType.DynamicVariable, name: dto.source.name, variablesReference: dto.source.variablesReference } - : { type: DataBreakpointSetType.Address, address: dto.source.address, bytes: dto.source.bytes }, + : dto.source.type === 'address' ? { type: DataBreakpointSetType.Address, address: dto.source.address, bytes: dto.source.bytes } + : dto.source.type === 'expression' ? { type: DataBreakpointSetType.Expression, expression: dto.source.expression } + : dto.source.frameId ? { type: DataBreakpointSetType.Scoped, expression: dto.source.expression, frameId: dto.source.frameId } + : dto.source.variablesReference ? { type: DataBreakpointSetType.Scoped, variable: dto.source.variable, variablesReference: dto.source.variablesReference } + : { type: DataBreakpointSetType.Variable, dataId: '' }, // should not happen condition: dto.condition, enabled: dto.enabled, hitCondition: dto.hitCondition, @@ -376,22 +378,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb return Promise.reject(new ErrorNoTelemetry('debug session not found')); } - public $getDataBreakpointInfo(sessionId: DebugSessionUUID, name: string, variablesReference?: number): Promise { - const session = this.debugService.getModel().getSession(sessionId, true); - if (session) { - return Promise.resolve(session.dataBreakpointInfo(name, variablesReference)); - } - return Promise.reject(new ErrorNoTelemetry('debug session not found')); - } - - public $getDataBytesBreakpointInfo(sessionId: DebugSessionUUID, address: string, bytes?: number): Promise { - const session = this.debugService.getModel().getSession(sessionId, true); - if (session) { - return Promise.resolve(session.dataBytesBreakpointInfo(address, bytes)); - } - return Promise.reject(new ErrorNoTelemetry('debug session not found')); - } - public $stopDebugging(sessionId: DebugSessionUUID | undefined): Promise { if (sessionId) { const session = this.debugService.getModel().getSession(sessionId, true); @@ -473,7 +459,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb condition: fbp.condition, hitCondition: fbp.hitCondition, logMessage: fbp.logMessage, - functionName: fbp.name + functionName: fbp.name, + mode: fbp.mode } satisfies IFunctionBreakpointDto; } else if ('src' in bp) { const dbp: IDataBreakpoint = bp; @@ -481,15 +468,19 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb type: 'data', id: dbp.getId(), source: dbp.src.type === DataBreakpointSetType.Variable ? { type: 'variable', dataId: dbp.src.dataId } - : dbp.src.type === DataBreakpointSetType.DynamicVariable ? { type: 'dynamicVariable', name: dbp.src.name, variablesReference: dbp.src.variablesReference } - : { type: 'address', address: dbp.src.address, bytes: dbp.src.bytes }, + : dbp.src.type === DataBreakpointSetType.Address ? { type: 'address', address: dbp.src.address, bytes: dbp.src.bytes } + : dbp.src.type === DataBreakpointSetType.Expression ? { type: 'expression', expression: dbp.src.expression } + : dbp.src.frameId ? { type: 'scoped', expression: dbp.src.expression, frameId: dbp.src.frameId } + : dbp.src.variablesReference ? { type: 'scoped', variable: dbp.src.variable, variablesReference: dbp.src.variablesReference } + : { type: 'variable', dataId: '' }, // should not happen enabled: dbp.enabled, condition: dbp.condition, hitCondition: dbp.hitCondition, logMessage: dbp.logMessage, accessType: dbp.accessType, label: dbp.description, - canPersist: dbp.canPersist + canPersist: dbp.canPersist, + mode: dbp.mode } satisfies IDataBreakpointDto; } else if ('uri' in bp) { const sbp: IBreakpoint = bp; @@ -503,6 +494,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb uri: sbp.uri, line: sbp.lineNumber > 0 ? sbp.lineNumber - 1 : 0, character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0, + mode: sbp.mode } satisfies ISourceBreakpointDto; } else { return undefined; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 52a406e2edb8f..ffd7dbf262717 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1632,8 +1632,6 @@ export interface MainThreadDebugServiceShape extends IDisposable { $setDebugSessionName(id: DebugSessionUUID, name: string): void; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise; $getDebugProtocolBreakpoint(id: DebugSessionUUID, breakpoinId: string): Promise; - $getDataBreakpointInfo(id: DebugSessionUUID, name: string, variablesReference?: number): Promise; - $getDataBytesBreakpointInfo(id: DebugSessionUUID, address: string, bytes?: number): Promise; $appendDebugConsole(value: string): void; $registerBreakpoints(breakpoints: Array): Promise; $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[], dataBreakpointIds: string[]): Promise; @@ -2394,8 +2392,6 @@ export interface IFunctionBreakpointDto extends IBreakpointDto { mode?: string; } -export type IDataBreakpointInfo = DebugProtocol.DataBreakpointInfoResponse['body']; - export interface IDataBreakpointDto extends IBreakpointDto { type: 'data'; source: vscode.DataBreakpointSource; diff --git a/src/vs/workbench/api/common/extHostDebugService.ts b/src/vs/workbench/api/common/extHostDebugService.ts index c03908f9de31f..9c2364d573714 100644 --- a/src/vs/workbench/api/common/extHostDebugService.ts +++ b/src/vs/workbench/api/common/extHostDebugService.ts @@ -31,6 +31,7 @@ import { IExtHostCommands } from './extHostCommands.js'; import * as Convert from './extHostTypeConverters.js'; import { coalesce } from '../../../base/common/arrays.js'; import { IExtHostTesting } from './extHostTesting.js'; +import { Mutable } from '../../../base/common/types.js'; export const IExtHostDebugService = createDecorator('IExtHostDebugService'); @@ -446,6 +447,20 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I functionName: bp.functionName, mode: bp.mode, }); + } else if (bp instanceof DataBreakpoint) { + dtos.push({ + type: 'data', + id: bp.id, + enabled: bp.enabled, + hitCondition: bp.hitCondition, + logMessage: bp.logMessage, + condition: bp.condition, + source: bp.source, + mode: bp.mode, + canPersist: bp.canPersist, + accessType: bp.accessType, + label: bp.label + }); } } @@ -756,21 +771,23 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I const bp = this._breakpoints.get(bpd.id); if (bp) { if (bp instanceof FunctionBreakpoint && bpd.type === 'function') { - const fbp = bp; + const fbp = >bp; fbp.enabled = bpd.enabled; fbp.condition = bpd.condition; fbp.hitCondition = bpd.hitCondition; fbp.logMessage = bpd.logMessage; fbp.functionName = bpd.functionName; + fbp.mode = bpd.mode; } else if (bp instanceof SourceBreakpoint && bpd.type === 'source') { - const sbp = bp; + const sbp = >bp; sbp.enabled = bpd.enabled; sbp.condition = bpd.condition; sbp.hitCondition = bpd.hitCondition; sbp.logMessage = bpd.logMessage; sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character)); + sbp.mode = bpd.mode; } else if (bp instanceof DataBreakpoint && bpd.type === 'data') { - const dbp = bp; + const dbp = >bp; dbp.enabled = bpd.enabled; dbp.condition = bpd.condition; dbp.hitCondition = bpd.hitCondition; @@ -778,6 +795,7 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I dbp.label = bpd.label; dbp.source = bpd.source; dbp.canPersist = bpd.canPersist; + dbp.mode = bpd.mode; dbp.accessType = bpd.accessType; } c.push(bp); @@ -1143,12 +1161,6 @@ export class ExtHostDebugSession { }, getDebugProtocolBreakpoint(breakpoint: vscode.Breakpoint): Promise { return that._debugServiceProxy.$getDebugProtocolBreakpoint(that._id, breakpoint.id); - }, - getDataBreakpointInfo(name: string, variablesReference?: number): Promise { - return that._debugServiceProxy.$getDataBreakpointInfo(that._id, name, variablesReference); - }, - getDataBytesBreakpointInfo(address: string, bytes?: number): Promise { - return that._debugServiceProxy.$getDataBytesBreakpointInfo(that._id, address, bytes); } }); } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 1037ced99a54f..7f72af8eda985 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -3088,7 +3088,10 @@ export class DataBreakpoint extends Breakpoint { this.label = label ? label : this.source.type === 'variable' ? `DataId '${this.source.dataId}'` : this.source.type === 'address' ? `Address '${this.source.address}${this.source.bytes ? `,${this.source.bytes}'` : ''}` - : `Variable '${this.source.name}${this.source.variablesReference ? `,${this.source.variablesReference}` : ''}'`; + : this.source.type === 'expression' ? `Expression '${this.source.expression}'` + : this.source.frameId ? `Scoped '${this.source.expression}@${this.source.frameId}'` + : this.source.variablesReference ? `Scoped '${this.source.variable}@${this.source.variablesReference}'` + : `Unknown data breakpoint`; } } @@ -4129,7 +4132,7 @@ export function validateTestCoverageCount(cc?: vscode.TestCoverageCount) { } if (cc.covered > cc.total) { - throw new Error(`The total number of covered items (${cc.covered}) cannot be greater than the total(${cc.total})`); + throw new Error(`The total number of covered items (${cc.covered}) cannot be greater than the total (${cc.total})`); } if (cc.total < 0) { diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 6aab855e6d3d8..aa410c01a229e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -553,8 +553,8 @@ export class DebugSession implements IDebugSession, IDisposable { return this._dataBreakpointInfo({ name: address, bytes, asAddress: true }); } - dataBreakpointInfo(name: string, variablesReference?: number): Promise { - return this._dataBreakpointInfo({ name, variablesReference }); + dataBreakpointInfo(name: string, variablesReference?: number, frameId?: number): Promise { + return this._dataBreakpointInfo({ name, variablesReference, frameId }); } private async _dataBreakpointInfo(args: DebugProtocol.DataBreakpointInfoArguments): Promise { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index da23fefcefecb..64a820f174087 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -432,7 +432,7 @@ export interface IDebugSession extends ITreeElement { sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise; sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise; - dataBreakpointInfo(name: string, variablesReference?: number): Promise; + dataBreakpointInfo(name: string, variablesReference?: number, frameId?: number): Promise; dataBytesBreakpointInfo(address: string, bytes?: number): Promise; sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise; sendInstructionBreakpoints(dbps: IInstructionBreakpoint[]): Promise; @@ -646,7 +646,8 @@ export interface IExceptionBreakpoint extends IBaseBreakpoint { export const enum DataBreakpointSetType { Variable, Address, - DynamicVariable + Expression, + Scoped } /** @@ -661,14 +662,6 @@ export type DataBreakpointSource = /** An identifier for the data. If it was retrieved using a `variablesReference` it may only be valid in the current suspended state, otherwise it's valid indefinitely. */ dataId: string; } - | { - /** The source type for address-based data breakpoints. This only works on sessions that have the `supportsDataBreakpointBytes` capability. */ - type: DataBreakpointSetType.DynamicVariable; - /** The name of the variable's child to obtain data breakpoint information for. If `variablesReference` isn't specified, this can be an expression. */ - name: string; - /** Reference to the variable container if the data breakpoint is requested for a child of the container. */ - variablesReference?: number; - } | { /** The source type for address-based data breakpoints. This only works on sessions that have the `supportsDataBreakpointBytes` capability. */ type: DataBreakpointSetType.Address; @@ -676,7 +669,32 @@ export type DataBreakpointSource = address: string; /** If specified, returns information for the range of memory extending `bytes` number of bytes from the address. */ bytes?: number; - }; + } + | { + /** The source type for address-based data breakpoints. This only works on sessions that have the `supportsDataBreakpointBytes` capability. */ + type: DataBreakpointSetType.Expression; + /** A global expression that is first evaluated when the breakpoint is activated. */ + expression: string; + } + | { + /** The source type for address-based data breakpoints. This only works on sessions that have the `supportsDataBreakpointBytes` capability. */ + type: DataBreakpointSetType.Scoped; + } & ( + | { + /** The name of the variable that is used for resolution. */ + variable: string; + /** Reference to the variable container that has the variable named `variable`. */ + variablesReference: number; + frameId?: never; + } + | { + /** The name of the expression that is used for resolution. */ + expression: string; + /** Reference to the stack frame to which the expression is scoped. */ + frameId: number; + variablesReference?: never; + } + ); export interface IDataBreakpoint extends IBaseBreakpoint { readonly description: string; diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index ed207fb7913da..ac9f994a47c31 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -1175,7 +1175,7 @@ export interface IDataBreakpointOptions extends IBaseBreakpointOptions { } export class DataBreakpoint extends BaseBreakpoint implements IDataBreakpoint { - private readonly sessionDataIdForAddr = new WeakMap(); + private readonly sessionDataId = new WeakMap(); public readonly description: string; public readonly src: DataBreakpointSource; @@ -1197,34 +1197,46 @@ export class DataBreakpoint extends BaseBreakpoint implements IDataBreakpoint { this.accessTypes = opts.accessTypes; this.accessType = opts.accessType; if (opts.initialSessionData) { - this.sessionDataIdForAddr.set(opts.initialSessionData.session, opts.initialSessionData.dataId); + this.sessionDataId.set(opts.initialSessionData.session, opts.initialSessionData.dataId); } } async toDAP(session: IDebugSession): Promise { - let dataId: string; - if (this.src.type === DataBreakpointSetType.Variable) { - dataId = this.src.dataId; - } else if (this.src.type === DataBreakpointSetType.DynamicVariable) { - let sessionDataId = this.sessionDataIdForAddr.get(session); - if (!sessionDataId) { - sessionDataId = (await session.dataBreakpointInfo(this.src.name, this.src.variablesReference))?.dataId; - if (!sessionDataId) { - return undefined; + let dataId = this.sessionDataId.get(session); + if (!dataId) { + if (this.src.type === DataBreakpointSetType.Variable) { + dataId = this.src.dataId; + } else if (this.src.type === DataBreakpointSetType.Address) { + const sessionDataId = (await session.dataBytesBreakpointInfo(this.src.address, this.src.bytes))?.dataId; + if (sessionDataId) { + this.sessionDataId.set(session, sessionDataId); + dataId = sessionDataId; } - this.sessionDataIdForAddr.set(session, sessionDataId); - } - dataId = sessionDataId; - } else { - let sessionDataId = this.sessionDataIdForAddr.get(session); - if (!sessionDataId) { - sessionDataId = (await session.dataBytesBreakpointInfo(this.src.address, this.src.bytes))?.dataId; - if (!sessionDataId) { - return undefined; + } else if (this.src.type === DataBreakpointSetType.Expression) { + const sessionDataId = (await session.dataBreakpointInfo(this.src.expression))?.dataId; + if (sessionDataId) { + this.sessionDataId.set(session, sessionDataId); + dataId = sessionDataId; + } + } else { + // type === DataBreakpointSetType.Scoped + if (this.src.frameId) { + const sessionDataId = (await session.dataBreakpointInfo(this.src.expression, undefined, this.src.frameId))?.dataId; + if (sessionDataId) { + this.sessionDataId.set(session, sessionDataId); + dataId = sessionDataId; + } + } else if (this.src.variablesReference) { + const sessionDataId = (await session.dataBreakpointInfo(this.src.variable, this.src.variablesReference))?.dataId; + if (sessionDataId) { + this.sessionDataId.set(session, sessionDataId); + dataId = sessionDataId; + } } - this.sessionDataIdForAddr.set(session, sessionDataId); } - dataId = sessionDataId; + } + if (!dataId) { + return; } return { diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 6ec9f85c83ee7..1b2d9a0c924c1 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -16083,24 +16083,6 @@ declare module 'vscode' { * @returns A promise that resolves to the Debug Adapter Protocol breakpoint or `undefined`. */ getDebugProtocolBreakpoint(breakpoint: Breakpoint): Thenable; - - /** - * Obtains information on a possible data breakpoint that could be set on an expression or variable. - * This will fail if the corresponding capability `supportsDataBreakpoints` is not supported by this session. - * - * @param name The name of the variable's child to obtain data breakpoint information for. If `variablesReference` isn't specified, this can be an expression. - * @param variablesReference Reference to the variable container if the data breakpoint is requested for a child of the container. - */ - getDataBreakpointInfo(name: string, variablesReference?: number): Thenable; - - /** - * Obtains information on a possible data breakpoint that could be set on an address for a given specified length. - * This will fail if the corresponding capability `supportsDataBreakpoints` and `supportsDataBreakpointBytes` is not supported by this session. - * - * @param address A memory address as a decimal value, or hex value if it is prefixed with `0x`. - * @param bytes If specified, returns information for the range of memory extending `bytes` number of bytes from the address. - */ - getDataBytesBreakpointInfo(address: string, bytes?: number): Thenable; } /** @@ -16466,90 +16448,6 @@ declare module 'vscode' { constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); } - /** - * Information on a possible data breakpoint. - */ - export interface DataBreakpointInfo { - /** An identifier for the data on which a data breakpoint can be created or null if no data breakpoint is available. Breakpoints added using the `dataId` may outlive the lifetime of the associated `dataId`. */ - dataId: string | null; - /** UI string that describes on what data the breakpoint is set on or why a data breakpoint is not available. */ - description: string; - /** Attribute lists the available access types for a potential data breakpoint. */ - accessTypes?: DataBreakpointAccessType[]; - /** Attribute indicates that a potential data breakpoint could be persisted across sessions. */ - canPersist?: boolean; - } - - /** - * The source for a data breakpoint. - */ - export type DataBreakpointSource = - | { - /** The source type for variable-based data breakpoints. */ - type: 'variable'; - /** An identifier for the data. If it was retrieved using a `variablesReference` it may only be valid in the current suspended state, otherwise it's valid indefinitely. */ - dataId: string; - } - | { - /** The source type for address-based data breakpoints. This only works on sessions that have the `supportsDataBreakpointBytes` capability. */ - type: 'address'; - /** A memory address as a decimal value, or hex value if it is prefixed with `0x`. */ - address: string; - /** If specified, returns information for the range of memory extending `bytes` number of bytes from the address. */ - bytes?: number; - } - | { - /** The source type for variables that are dynamically resolved when the breakpoint is activated. */ - type: 'dynamicVariable'; - /** The name of the variable's child to obtain data breakpoint information for. If `variablesReference` isn't specified, this can be an expression. */ - name: string; - /** Reference to the variable container if the data breakpoint is requested for a child of the container. */ - variablesReference?: number; - }; - - - /** - * A breakpoint specified by a variable or memory change. - */ - export class DataBreakpoint extends Breakpoint { - /** - * The human-readable label for the data breakpoint. - */ - label: string; - - /** - * The source for the data breakpoint. If the `dataId` is known already, it can be specified directly using the `variable` type. Alternatively, VSCode may resolve the `dataId` based on the address or dynamic variable that is specified. - */ - source: DataBreakpointSource; - - /** - * Flag to indicate if the data breakpoint could be persisted across sessions. - */ - canPersist: boolean; - - /** - * The access type of the data. - */ - accessType: DataBreakpointAccessType; - - /** - * Create a new data breakpoint. - * - * @param source The source for the data breakpoint. If the `dataId` is known already, it can be specified directly. If the dataId is not known, it can be retrieved via the `getDataBreakpointInfo` or `getDataBytesBreakpointInfo` request from the session. Alternatively, an address or variable can be specified as source which will be resolved in the context of the session in a similar manner. - * @param accessType The access type of the data breakpoint. - * @param canPersist Flag to indicate if the data breakpoint could be persisted across sessions. - * @param label The human-readable label for the data breakpoint. - * @param enabled Is breakpoint enabled. - * @param condition Expression for conditional breakpoints. - * @param hitCondition Expression that controls how many hits of the breakpoint are ignored. - * @param logMessage Log message to display when breakpoint is hit. - */ - constructor(source: DataBreakpointSource | string, accessType: DataBreakpointAccessType, canPersist?: boolean, label?: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); - } - - /** Access type for data breakpoints. */ - export type DataBreakpointAccessType = 'read' | 'write' | 'readWrite'; - /** * Debug console mode used by debug session, see {@link DebugSessionOptions options}. */ diff --git a/src/vscode-dts/vscode.proposed.debugDataBreakpoints.d.ts b/src/vscode-dts/vscode.proposed.debugDataBreakpoints.d.ts new file mode 100644 index 0000000000000..5f1f6a32bd597 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.debugDataBreakpoints.d.ts @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/195151 + + /** + * The source for a data breakpoint. + */ + export type DataBreakpointSource = + | { + /** The source type for fixed data identifiers that do not need to be re-resolved when the breakpoint is activated. */ + type: 'variable'; + /** An identifier for the data. If it was retrieved using a `variablesReference` it may only be valid in the current suspended state, otherwise it's valid indefinitely. */ + dataId: string; + } + | { + /** The source type for address-based data breakpoints. Address-based data breakpoints are re-resolved when the breakpoint is activated. This type only applies to sessions that have the `supportsDataBreakpointBytes` capability. */ + type: 'address'; + /** A memory address as a decimal value, or hex value if it is prefixed with `0x`. */ + address: string; + /** If specified, returns information for the range of memory extending `bytes` number of bytes from the address. */ + bytes?: number; + } + | { + /** The source type for expressions that are dynamically resolved when the breakpoint is activated. */ + type: 'expression'; + /** A global expression that is first evaluated when the breakpoint is activated. */ + expression: string; + } + | { + /** The source type for scoped variables and expressions that are dynamically resolved when the breakpoint is activated. */ + type: 'scoped'; + } & ( + | { + /** The name of the variable that is used for resolution. */ + variable: string; + /** Reference to the variable container that has the variable named `variable`. */ + variablesReference: number; + frameId?: never; + } + | { + /** The name of the expression that is used for resolution. */ + expression: string; + /** Reference to the stack frame to which the expression is scoped. */ + frameId: number; + variablesReference?: never; + } + ); + + + /** Access type for data breakpoints. */ + export type DataBreakpointAccessType = 'read' | 'write' | 'readWrite'; + + /** + * A breakpoint specified by a variable or memory change. + */ + export class DataBreakpoint extends Breakpoint { + /** + * The human-readable label for the data breakpoint. + */ + label: string; + + /** + * The source for the data breakpoint. See the different source types on how they are resolved during breakpoint activation. + */ + source: DataBreakpointSource; + + /** + * Flag to indicate if the data breakpoint could be persisted across sessions. + */ + canPersist: boolean; + + /** + * The access type of the data. + */ + accessType: DataBreakpointAccessType; + + /** + * Create a new data breakpoint. + * + * @param source The source for the data breakpoint. If the `dataId` is known already, it can be specified directly. If the dataId is not known, it can be retrieved via a data breakpoint info request from the session. Alternatively, some sources offer dynamic resolution during breakpoint activation. + * @param accessType The access type of the data breakpoint. + * @param canPersist Flag to indicate if the data breakpoint could be persisted across sessions. + * @param label The human-readable label for the data breakpoint. + * @param enabled Is breakpoint enabled. + * @param condition Expression for conditional breakpoints. + * @param hitCondition Expression that controls how many hits of the breakpoint are ignored. + * @param logMessage Log message to display when breakpoint is hit. + */ + constructor(source: DataBreakpointSource | string, accessType: DataBreakpointAccessType, canPersist?: boolean, label?: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); + } +}