Skip to content

Commit 723e2f4

Browse files
Strict null checks (#986)
* initial cleanup * strict nulls checks on and corresponding fixes * linter fixes * eol fix * assert the variable in variables manager * more simplifications EOL fixes * cleanup esm migration leftover * updating typescript to better handle strictNullCheck * eslint & decoder type log * parse_variable fix * bad merge fix * fix expanding variable & add corresponding missing testcase * fixing the issue with array elements --------- Co-authored-by: David Kincaid <daelonsuzuka@gmail.com>
1 parent a58d0e4 commit 723e2f4

43 files changed

Lines changed: 972 additions & 719 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
],
4646
"quotes": [
4747
"warn",
48-
"double"
48+
"double",
49+
{ "avoidEscape": true }
4950
],
5051
"semi": [
5152
"error",

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@
919919
"ts-node": "^10.9.1",
920920
"tsconfig-paths": "^4.2.0",
921921
"tslint": "^5.20.1",
922-
"typescript": "^5.2.2"
922+
"typescript": "^5.9.3"
923923
},
924924
"dependencies": {
925925
"@vscode/debugadapter": "^1.68.0",

src/debugger/debug_runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export class GodotDebugData {
101101
id: this.breakpoint_id++,
102102
};
103103

104-
let bps: GodotBreakpoint[] = this.breakpoints.get(bp.file);
104+
let bps: GodotBreakpoint[] | undefined = this.breakpoints.get(bp.file);
105105
if (!bps) {
106106
bps = [];
107107
this.breakpoints.set(bp.file, bps);

src/debugger/debugger.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
5858
additional_options: string;
5959
}
6060

61-
export let pinnedScene: Uri;
61+
export let pinnedScene: Uri | undefined;
6262

6363
class GDFileDecorationProvider implements FileDecorationProvider {
6464
private emitter = new EventEmitter<Uri>();
@@ -70,7 +70,7 @@ class GDFileDecorationProvider implements FileDecorationProvider {
7070

7171
provideFileDecoration(uri: Uri, token: CancellationToken): FileDecoration | undefined {
7272
if (uri.scheme !== "file") return undefined;
73-
if (pinnedScene && uri.fsPath === pinnedScene.fsPath) {
73+
if (pinnedScene !== undefined && uri.fsPath === pinnedScene.fsPath) {
7474
return {
7575
badge: "🖈",
7676
};
@@ -100,8 +100,8 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
100100
register_command("debugger.editValue", this.edit_value.bind(this)),
101101
register_command("debugger.debugCurrentFile", this.debug_current_file.bind(this)),
102102
register_command("debugger.debugPinnedFile", this.debug_pinned_file.bind(this)),
103-
register_command("debugger.pinFile", this.pin_file.bind(this)),
104-
register_command("debugger.unpinFile", this.unpin_file.bind(this)),
103+
register_command("debugger.pinFile", this.pinFile.bind(this)),
104+
register_command("debugger.unpinFile", this.unpinFile.bind(this)),
105105
register_command("debugger.openPinnedFile", this.open_pinned_file.bind(this)),
106106
this.inspector.view,
107107
this.sceneTree.view,
@@ -113,7 +113,7 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
113113
const projectVersion = await get_project_version();
114114
log.info(`Project version identified as ${projectVersion}`);
115115

116-
if (projectVersion.startsWith("4")) {
116+
if (projectVersion?.startsWith("4")) {
117117
this.session = new Godot4DebugSession(projectVersion);
118118
} else {
119119
this.session = new Godot3DebugSession();
@@ -168,13 +168,13 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
168168
public debug_current_file() {
169169
log.info("Attempting to debug current file");
170170
const configs: DebugConfiguration[] = workspace
171-
.getConfiguration("launch", window.activeTextEditor.document.uri)
172-
.get("configurations");
171+
.getConfiguration("launch", window.activeTextEditor?.document.uri)
172+
.get("configurations") || [];
173173
const launches = configs.filter((c) => c.request === "launch");
174174
const currents = configs.filter((c) => c.scene === "current");
175175

176-
let path = window.activeTextEditor.document.fileName;
177-
if (path.endsWith(".gd")) {
176+
let path = window.activeTextEditor?.document.fileName;
177+
if (path?.endsWith(".gd")) {
178178
const scenePath = path.replace(".gd", ".tscn");
179179
if (!fs.existsSync(scenePath)) {
180180
const message = `Can't launch debug session: no associated scene for '${path}'. (Script and scene file must have the same name.)`;
@@ -196,12 +196,12 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
196196
config.scene = path;
197197

198198
log.info(`Starting debug session for '${path}'`);
199-
debug.startDebugging(workspace.workspaceFolders[0], config);
199+
debug.startDebugging(workspace.workspaceFolders?.[0], config);
200200
}
201201

202202
public debug_pinned_file() {
203203
log.info("Attempting to debug pinned scene");
204-
const configs: DebugConfiguration[] = workspace.getConfiguration("launch", pinnedScene).get("configurations");
204+
const configs: DebugConfiguration[] = workspace.getConfiguration("launch", pinnedScene).get("configurations") || [];
205205
const launches = configs.filter((c) => c.request === "launch");
206206
const currents = configs.filter((c) => c.scene === "pinned");
207207

@@ -231,13 +231,17 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
231231
config.scene = path;
232232

233233
log.info(`Starting debug session for '${path}'`);
234-
debug.startDebugging(workspace.workspaceFolders[0], config);
234+
debug.startDebugging(workspace.workspaceFolders?.[0], config);
235235
}
236236

237-
public pin_file(uri: Uri) {
237+
public pinFile(uri: Uri | undefined) {
238238
let _uri = uri;
239239
if (uri === undefined) {
240-
_uri = window.activeTextEditor.document.uri;
240+
_uri = window.activeTextEditor?.document.uri;
241+
}
242+
if (_uri === undefined) {
243+
window.showWarningMessage("No active editor. Open a file to pin it.");
244+
return;
241245
}
242246
log.info(`Pinning debug target file: '${_uri.fsPath}'`);
243247
set_context("pinnedScene", [_uri.fsPath]);
@@ -249,17 +253,19 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
249253
this.fileDecorations.update(_uri);
250254
}
251255

252-
public unpin_file(uri: Uri) {
256+
public unpinFile(uri: Uri) {
253257
log.info(`Unpinning debug target file: '${pinnedScene}'`);
254258
set_context("pinnedScene", []);
255259
const previousPinnedScene = pinnedScene;
256260
pinnedScene = undefined;
257261
this.context.workspaceState.update("pinnedScene", pinnedScene);
258-
this.fileDecorations.update(previousPinnedScene);
262+
if (previousPinnedScene) {
263+
this.fileDecorations.update(previousPinnedScene);
264+
}
259265
}
260266

261267
public restore_pinned_file() {
262-
pinnedScene = this.context.workspaceState.get("pinnedScene", undefined);
268+
pinnedScene = this.context.workspaceState.get<Uri>("pinnedScene");
263269
if (pinnedScene) {
264270
log.info(`Restoring pinned debug target file: '${pinnedScene.fsPath}'`);
265271
set_context("pinnedScene", [pinnedScene.fsPath]);
@@ -278,6 +284,10 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
278284
}
279285

280286
private async fill_inspector(element: SceneNode | RemoteProperty, force_refresh = false) {
287+
if (element.object_id === undefined) {
288+
return;
289+
}
290+
281291
if (this.session instanceof Godot4DebugSession) {
282292
const godot_object = await this.session.variables_manager?.get_godot_object(
283293
BigInt(element.object_id),
@@ -313,11 +323,17 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
313323
public async refresh_inspector() {
314324
if (this.inspector.has_tree()) {
315325
const item = this.inspector.get_top_item();
316-
await this.fill_inspector(item, /*force_refresh*/ true);
326+
if (item) {
327+
await this.fill_inspector(item, /*force_refresh*/ true);
328+
}
317329
}
318330
}
319331

320332
public async edit_value(property: RemoteProperty) {
333+
if (property.object_id === undefined) {
334+
log.error("Invalid property to edit (property.object_id === undefined)");
335+
return;
336+
}
321337
const previous_value = property.value;
322338
const type = typeof previous_value;
323339
const is_float = type === "number" && !Number.isInteger(previous_value);
@@ -328,6 +344,9 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
328344
new_parsed_value = value;
329345
break;
330346
case "number":
347+
if (!value) {
348+
return;
349+
}
331350
if (is_float) {
332351
new_parsed_value = Number.parseFloat(value);
333352
if (Number.isNaN(new_parsed_value)) {
@@ -341,19 +360,26 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
341360
}
342361
break;
343362
case "boolean":
363+
if (!value) {
364+
return;
365+
}
344366
if (value.toLowerCase() === "true" || value.toLowerCase() === "false") {
345367
new_parsed_value = value.toLowerCase() === "true";
346368
} else if (value === "0" || value === "1") {
347369
new_parsed_value = value === "1";
348370
} else {
349371
return;
350372
}
373+
break;
351374
}
352-
if (property.changes_parent) {
375+
if (property.changes_parent && property.parent !== undefined) {
353376
const parents = [property.parent];
354377
let idx = 0;
355378
while (parents[idx].changes_parent) {
356-
parents.push(parents[idx++].parent);
379+
const parent = parents[idx++].parent;
380+
if (parent) {
381+
parents.push(parent);
382+
}
357383
}
358384
const changed_value = this.inspector.get_changed_value(parents, property, new_parsed_value);
359385
this.session?.controller.set_object_property(BigInt(property.object_id), parents[idx].label, changed_value);
@@ -362,9 +388,11 @@ export class GodotDebugger implements DebugAdapterDescriptorFactory, DebugConfig
362388
}
363389

364390
const item = this.inspector.get_top_item();
365-
await this.fill_inspector(item, /*force_refresh*/ true);
391+
if (item) {
392+
await this.fill_inspector(item, /*force_refresh*/ true);
393+
}
366394

367395
// const res = await debug.activeDebugSession?.customRequest("refreshVariables"); // refresh vscode.debug variables
368-
this.session.sendEvent(new InvalidatedEvent(["variables"]));
396+
this.session?.sendEvent(new InvalidatedEvent(["variables"]));
369397
}
370398
}

0 commit comments

Comments
 (0)