Skip to content

Conversation

@PabstMirror
Copy link
Collaborator

ref #1168

  • Run loops twice, first time with errors suppressed in sub-scopes
  • simplify passing Database around
private _oldLoc = false;
{
    _x params ["_locNew", "_colorNew"];
    if (_oldLoc isNotEqualTo false) then {
        drawLine3D [_oldLoc, _locNew, _colorNew]; // safe because it happens inside an inner if-scope
    };
    _oldLoc = _locNew;
} forEach x_points;

private _oldLoc2 = false;
{
    _x params ["_locNew", "_colorNew"];
    drawLine3D [_oldLoc2, _locNew, _colorNew]; // error
    _oldLoc2 = _locNew;
} forEach x_points;

@codecov
Copy link

codecov bot commented Jan 2, 2026

Codecov Report

❌ Patch coverage is 95.37037% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.9%. Comparing base (765384f) to head (22fcb71).

Files with missing lines Patch % Lines
libs/sqf/src/analyze/inspector/commands.rs 92.8% 2 Missing ⚠️
libs/sqf/src/analyze/inspector/mod.rs 97.1% 2 Missing ⚠️
...bs/sqf/src/analyze/inspector/external_functions.rs 88.8% 1 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
...bs/sqf/src/analyze/inspector/external_functions.rs 73.8% <88.8%> (-0.5%) ⬇️
libs/sqf/src/analyze/inspector/commands.rs 84.4% <92.8%> (-0.4%) ⬇️
libs/sqf/src/analyze/inspector/mod.rs 96.8% <97.1%> (-0.3%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces false positives in the SQF inspector for variables that are initialized within loop iterations. The main approach is to run loop bodies twice: first with error suppression enabled to allow variables to be assigned, then a second time with normal error checking to catch genuine issues.

Changes:

  • Added lifetime parameter to Inspector struct and stored Database as a field to simplify passing it through method calls
  • Implemented loop detection and double-execution logic with error suppression for the first run
  • Added test cases demonstrating safe vs unsafe usage patterns in loops

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
libs/sqf/src/analyze/inspector/mod.rs Added errors_suppressed tracking to ScriptScope, stored Database as field, modified stack_push to accept test_run parameter, implemented error_insert method with suppression logic
libs/sqf/src/analyze/inspector/commands.rs Added is_loop parameter to loop-related commands, implemented double-execution logic in cmd_generic_call and cmd_b_do, removed database parameters
libs/sqf/src/analyze/inspector/external_functions.rs Removed database parameters from method signatures, updated to use self.database
libs/sqf/tests/inspector/test_iteration.sqf Added test cases for safe variable usage within loops (lines 28-62)
libs/sqf/tests/snapshots/inspector__tests__iteration.snap Updated snapshot to reflect new test case with expected error

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +161 to +173
pub fn error_insert(&mut self, issue: Issue) {
// skip if errors are suppressed in any parent scope
if self
.active_scope()
.errors_suppressed
.iter()
.rev()
.skip(1)
.all(|s| !*s)
{
self.errors.insert(issue);
}
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The skip(1) in the error suppression check skips the current stack frame, which means errors won't be suppressed in the immediate loop body where test_run is true. The logic should check all frames including the current one. Remove .skip(1) so that if self.active_scope().errors_suppressed.iter().rev().all(|s| !*s) checks all frames.

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +240
if is_loop {
// repeat the loop, but with error suppression off
return self.cmd_generic_call(code_possibilities, magic_opt, false);
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recursive call to cmd_generic_call will re-execute the loop body, but the variable assignments from the first run remain in the stack. This means variables assigned in the first run (like _oldLoc becoming _locNew) will still be set during the second run, which defeats the purpose of detecting uninitialized variable errors. The variable state should be restored or the stack should be reset between runs.

Copilot uses AI. Check for mistakes.
Comment on lines +311 to +314
if is_loop {
// repeat the loop, but with error suppression off
return self.cmd_b_do(lhs, rhs, false);
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the issue in cmd_generic_call, this recursive call to cmd_b_do will re-execute the loop body with variable assignments from the first run still present in the stack, which may hide errors that should be detected. The variable state should be managed between the two runs.

Copilot uses AI. Check for mistakes.
pub fn stack_push(
&mut self,
expression_opt: Option<&Expression>,
test_run: bool,
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter name test_run is ambiguous. Consider renaming it to suppress_errors or is_test_iteration to more clearly indicate its purpose of suppressing error reporting during the first iteration of loop analysis.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants