From b5ff5a17fd22e273aa989b1697d40492d6bc244d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 13:52:26 -0800 Subject: [PATCH] Strict null work in debug --- src/tsconfig.strictNullChecks.json | 9 ++++++ .../contrib/debug/browser/debugActionItems.ts | 7 +++-- .../debug/browser/debugContentProvider.ts | 10 +++---- .../contrib/debug/browser/exceptionWidget.ts | 6 ++-- .../debug/browser/statusbarColorProvider.ts | 3 ++ .../workbench/contrib/debug/common/debug.ts | 2 +- .../contrib/debug/common/debugSchemas.ts | 2 +- .../contrib/debug/common/debugUtils.ts | 4 +-- .../contrib/debug/common/debugViewModel.ts | 4 +-- .../electron-browser/breakpointWidget.ts | 4 +-- .../debug/electron-browser/rawDebugSession.ts | 23 ++++++++++----- .../contrib/debug/node/debugAdapter.ts | 29 ++++++++++--------- 12 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 43e2ec14c54..0fea9d867ea 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -517,11 +517,20 @@ "./vs/workbench/contrib/comments/electron-browser/commentService.ts", "./vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts", "./vs/workbench/contrib/debug/browser/debugANSIHandling.ts", + "./vs/workbench/contrib/debug/browser/debugActionItems.ts", + "./vs/workbench/contrib/debug/browser/debugContentProvider.ts", + "./vs/workbench/contrib/debug/browser/debugStatus.ts", + "./vs/workbench/contrib/debug/browser/exceptionWidget.ts", "./vs/workbench/contrib/debug/browser/linkDetector.ts", + "./vs/workbench/contrib/debug/browser/statusbarColorProvider.ts", "./vs/workbench/contrib/debug/common/debug.ts", "./vs/workbench/contrib/debug/common/debugProtocol.d.ts", + "./vs/workbench/contrib/debug/common/debugSchemas.ts", "./vs/workbench/contrib/debug/common/debugSource.ts", "./vs/workbench/contrib/debug/common/debugUtils.ts", + "./vs/workbench/contrib/debug/common/debugViewModel.ts", + "./vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts", + "./vs/workbench/contrib/debug/node/debugAdapter.ts", "./vs/workbench/contrib/debug/node/telemetryApp.ts", "./vs/workbench/contrib/debug/test/common/debugSource.test.ts", "./vs/workbench/contrib/debug/test/common/debugUtils.test.ts", diff --git a/src/vs/workbench/contrib/debug/browser/debugActionItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts index 07298620ba1..574fec93f5b 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts @@ -31,7 +31,7 @@ export class StartDebugActionItem implements IActionItem { private container: HTMLElement; private start: HTMLElement; private selectBox: SelectBox; - private options: { label: string, handler: (() => boolean) }[]; + private options: { label: string, handler?: (() => boolean) }[]; private toDispose: IDisposable[]; private selected: number; @@ -46,7 +46,7 @@ export class StartDebugActionItem implements IActionItem { @IContextViewService contextViewService: IContextViewService, ) { this.toDispose = []; - this.selectBox = new SelectBox([], -1, contextViewService, null, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); + this.selectBox = new SelectBox([], -1, contextViewService, undefined, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); this.toDispose.push(this.selectBox); this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService, { selectBackground: SIDE_BAR_BACKGROUND @@ -102,7 +102,8 @@ export class StartDebugActionItem implements IActionItem { } })); this.toDispose.push(this.selectBox.onDidSelect(e => { - const shouldBeSelected = this.options[e.index].handler(); + const target = this.options[e.index]; + const shouldBeSelected = target.handler ? target.handler() : false; if (shouldBeSelected) { this.selected = e.index; } else { diff --git a/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts b/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts index 5909b232d63..37859760d0e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts @@ -52,7 +52,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC this.pendingUpdates.forEach(cancellationSource => cancellationSource.dispose()); } - provideTextContent(resource: uri): Promise { + provideTextContent(resource: uri): Promise | null { return this.createOrUpdateContentModel(resource, true); } @@ -69,15 +69,15 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC /** * Create or reload the model content of the given resource. */ - private createOrUpdateContentModel(resource: uri, createIfNotExists: boolean): Promise { + private createOrUpdateContentModel(resource: uri, createIfNotExists: boolean): Promise | null { const model = this.modelService.getModel(resource); if (!model && !createIfNotExists) { // nothing to do - return undefined; + return null; } - let session: IDebugSession; + let session: IDebugSession | undefined; if (resource.query) { const data = Source.getEncodedDebugData(resource); @@ -125,7 +125,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC // remove token this.pendingUpdates.delete(model.id); - if (!myToken.token.isCancellationRequested && edits.length > 0) { + if (!myToken.token.isCancellationRequested && edits && edits.length > 0) { // use the evil-edit as these models show in readonly-editor only model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); } diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index 1b971255d7e..7148fa39200 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -24,7 +24,7 @@ export const debugExceptionWidgetBackground = registerColor('debugExceptionWidge export class ExceptionWidget extends ZoneWidget { - private _backgroundColor: Color; + private _backgroundColor?: Color; constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, @IThemeService themeService: IThemeService, @@ -55,7 +55,7 @@ export class ExceptionWidget extends ZoneWidget { protected _applyStyles(): void { if (this.container) { - this.container.style.backgroundColor = this._backgroundColor.toString(); + this.container.style.backgroundColor = this._backgroundColor ? this._backgroundColor.toString() : ''; } super._applyStyles(); } @@ -86,7 +86,7 @@ export class ExceptionWidget extends ZoneWidget { } } - protected _doLayout(heightInPixel: number, widthInPixel: number): void { + protected _doLayout(_heightInPixel: number | undefined, _widthInPixel: number | undefined): void { // Reload the height with respect to the exception text content and relayout it to match the line count. this.container.style.height = 'initial'; diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index 7ee9bf99083..ad02a131722 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -57,6 +57,9 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri super.updateStyles(); const container = this.partService.getContainer(Parts.STATUSBAR_PART); + if (!container) { + return; + } if (isStatusbarInDebugMode(this.debugService)) { addClass(container, 'debugging'); } else { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 0e629cd2d1b..7a34a6e28f2 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -461,7 +461,7 @@ export interface ICompound { export interface IDebugAdapter extends IDisposable { readonly onError: Event; - readonly onExit: Event; + readonly onExit: Event; onRequest(callback: (request: DebugProtocol.Request) => void); onEvent(callback: (event: DebugProtocol.Event) => void); startSession(): Promise; diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 6788b899874..1969ba6b5b9 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -195,6 +195,6 @@ export const launchSchema: IJSONSchema = { defaultCompound ] }, - inputs: inputsSchema.definitions.inputs + inputs: inputsSchema.definitions!.inputs } }; diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index b1b54612c29..fccd81a0add 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -73,10 +73,10 @@ export function getExactExpressionStartAndEnd(lineContent: string, looseStart: n // RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt const _schemePattern = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/; -export function isUri(s: string) { +export function isUri(s: string | undefined): boolean { // heuristics: a valid uri starts with a scheme and // the scheme has at least 2 characters so that it doesn't look like a drive letter. - return s && s.match(_schemePattern); + return !!(s && s.match(_schemePattern)); } function stringToUri(path: string): string { diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index d65b9d9ae09..8296124dfb9 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -58,7 +58,7 @@ export class ViewModel implements IViewModel { this._focusedThread = thread; this._focusedSession = session; - this.loadedScriptsSupportedContextKey.set(session && session.capabilities.supportsLoadedSourcesRequest); + this.loadedScriptsSupportedContextKey.set(session ? !!session.capabilities.supportsLoadedSourcesRequest : false); if (shouldEmitForSession) { this._onDidFocusSession.fire(session); @@ -68,7 +68,7 @@ export class ViewModel implements IViewModel { } } - get onDidFocusSession(): Event { + get onDidFocusSession(): Event { return this._onDidFocusSession.event; } diff --git a/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts index f2aa24229b2..8998aca5b83 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts @@ -53,7 +53,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi private conditionInput = ''; private hitCountInput = ''; private logMessageInput = ''; - private breakpoint: IBreakpoint; + private breakpoint?: IBreakpoint; constructor(editor: ICodeEditor, private lineNumber: number, private context: Context, @IContextViewService private readonly contextViewService: IContextViewService, @@ -102,7 +102,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi } } - private getInputValue(breakpoint: IBreakpoint): string { + private getInputValue(breakpoint: IBreakpoint | undefined): string { switch (this.context) { case Context.LOG_MESSAGE: return breakpoint && breakpoint.logMessage ? breakpoint.logMessage : this.logMessageInput; diff --git a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts index 8b28b1564f2..15fac60c1cf 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts @@ -64,14 +64,16 @@ export class RawDebugSession { // DA events private readonly _onDidExitAdapter: Emitter; + private debugAdapter: IDebugAdapter | null; constructor( - private debugAdapter: IDebugAdapter, + debugAdapter: IDebugAdapter, dbgr: IDebugger, private telemetryService: ITelemetryService, public customTelemetryService: ITelemetryService, private environmentService: IEnvironmentService ) { + this.debugAdapter = debugAdapter; this._capabilities = Object.create(null); this._readyForBreakpoints = false; this.inShutdown = false; @@ -224,6 +226,9 @@ export class RawDebugSession { * Starts the underlying debug adapter and tracks the session time for telemetry. */ public start(): Promise { + if (!this.debugAdapter) { + return Promise.reject(new Error('no debug adapter')); + } return this.debugAdapter.startSession().then(() => { this.startTime = new Date().getTime(); }, err => { @@ -560,7 +565,7 @@ export class RawDebugSession { let spawnArgs = vscodeArgs.args.map(a => { if ((a.prefix === '--file-uri=' || a.prefix === '--folder-uri=') && !isUri(a.path)) { - return a.path; + return (a.path || ''); } return (a.prefix || '') + (a.path || ''); }); @@ -622,6 +627,10 @@ export class RawDebugSession { private send(command: string, args: any, timeout?: number): Promise { return new Promise((completeDispatch, errorDispatch) => { + if (!this.debugAdapter) { + errorDispatch(new Error('no debug adapter found')); + return; + } this.debugAdapter.sendRequest(command, args, (response: R) => { if (response.success) { completeDispatch(response); @@ -639,7 +648,7 @@ export class RawDebugSession { } const error = errorResponse && errorResponse.body ? errorResponse.body.error : null; - const errorMessage = errorResponse ? errorResponse.message : ''; + const errorMessage = errorResponse ? errorResponse.message || '' : ''; if (error && error.sendTelemetry) { const telemetryMessage = error ? formatPII(error.format, true, error.variables) : errorMessage; @@ -650,7 +659,7 @@ export class RawDebugSession { if (error && error.url) { const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info"); return createErrorWithActions(userMessage, { - actions: [new Action('debug.moreInfo', label, null, true, () => { + actions: [new Action('debug.moreInfo', label, undefined, true, () => { window.open(error.url); return Promise.resolve(null); })] @@ -660,7 +669,7 @@ export class RawDebugSession { return new Error(userMessage); } - private mergeCapabilities(capabilities: DebugProtocol.Capabilities): void { + private mergeCapabilities(capabilities: DebugProtocol.Capabilities | undefined): void { if (capabilities) { this._capabilities = objects.mixin(this._capabilities, capabilities); } @@ -674,11 +683,11 @@ export class RawDebugSession { threadId, allThreadsContinued }, - seq: undefined + seq: undefined! }); } - private telemetryDebugProtocolErrorResponse(telemetryMessage: string) { + private telemetryDebugProtocolErrorResponse(telemetryMessage: string | undefined) { /* __GDPR__ "debugProtocolErrorResponse" : { "error" : { "classification": "CallstackOrException", "purpose": "FeatureInsight" } diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index c6948364d4e..09939841def 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -31,7 +31,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { private messageCallback: (message: DebugProtocol.ProtocolMessage) => void; protected readonly _onError: Emitter; - protected readonly _onExit: Emitter; + protected readonly _onExit: Emitter; constructor() { this.sequence = 1; @@ -50,7 +50,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { return this._onError.event; } - get onExit(): Event { + get onExit(): Event { return this._onExit.event; } @@ -255,7 +255,7 @@ export abstract class StreamDebugAdapter extends AbstractDebugAdapter { */ export class SocketDebugAdapter extends StreamDebugAdapter { - private socket: net.Socket; + private socket?: net.Socket; constructor(private adapterServer: IDebugAdapterServer) { super(); @@ -265,8 +265,8 @@ export class SocketDebugAdapter extends StreamDebugAdapter { return new Promise((resolve, reject) => { let connected = false; this.socket = net.createConnection(this.adapterServer.port, this.adapterServer.host || '127.0.0.1', () => { - this.connect(this.socket, this.socket); - resolve(null); + this.connect(this.socket!, this.socket!); + resolve(); connected = true; }); this.socket.on('close', () => { @@ -306,7 +306,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { private serverProcess: cp.ChildProcess; - constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private outputService?: IOutputService) { + constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private readonly outputService?: IOutputService) { super(); } @@ -354,7 +354,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { reject(new Error(nls.localize('unableToLaunchDebugAdapter', "Unable to launch debug adapter from '{0}'.", this.adapterExecutable.args[0]))); } this.serverProcess = child; - resolve(null); + resolve(); } else { reject(new Error(nls.localize('unableToLaunchDebugAdapterNoArgs', "Unable to launch debug adapter."))); } @@ -366,7 +366,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { options.cwd = this.adapterExecutable.options.cwd; } this.serverProcess = cp.spawn(this.adapterExecutable.command, this.adapterExecutable.args, options); - resolve(null); + resolve(); } }).then(_ => { this.serverProcess.on('error', err => { @@ -387,13 +387,14 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { this._onError.fire(error); }); - if (this.outputService) { + const outputService = this.outputService; + if (outputService) { const sanitize = (s: string) => s.toString().replace(/\r?\n$/mg, ''); // this.serverProcess.stdout.on('data', (data: string) => { // console.log('%c' + sanitize(data), 'background: #ddd; font-style: italic;'); // }); this.serverProcess.stderr.on('data', (data: string) => { - this.outputService.getChannel(ExtensionsChannelId).append(sanitize(data)); + outputService.getChannel(ExtensionsChannelId).append(sanitize(data)); }); } @@ -431,7 +432,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } } - private static extract(contribution: IDebuggerContribution, extensionFolderPath: string): IDebuggerContribution { + private static extract(contribution: IDebuggerContribution, extensionFolderPath: string): IDebuggerContribution | undefined { if (!contribution) { return undefined; } @@ -485,7 +486,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { if (ed.contributes) { const debuggers = ed.contributes['debuggers']; if (debuggers && debuggers.length > 0) { - debuggers.filter(dbg => strings.equalsIgnoreCase(dbg.type, debugType)).forEach(dbg => { + debuggers.filter(dbg => typeof dbg.type === 'string' && strings.equalsIgnoreCase(dbg.type, debugType)).forEach(dbg => { // extract relevant attributes and make then absolute where needed const extractedDbg = ExecutableDebugAdapter.extract(dbg, ed.extensionLocation.fsPath); @@ -497,7 +498,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } // select the right platform - let platformInfo: IPlatformSpecificAdapterContribution; + let platformInfo: IPlatformSpecificAdapterContribution | undefined; if (platform.isWindows && !process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432')) { platformInfo = result.winx86 || result.win || result.windows; } else if (platform.isWindows) { @@ -519,7 +520,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { return { type: 'executable', command: runtime, - args: (runtimeArgs || []).concat([program]).concat(args || []) + args: (runtimeArgs || []).concat(typeof program === 'string' ? [program] : []).concat(args || []) }; } else if (program) { return { -- GitLab