diff --git a/libs/sqf/src/analyze/lints/s08_format_args.rs b/libs/sqf/src/analyze/lints/s08_format_args.rs index d95e961f..34d66ebe 100644 --- a/libs/sqf/src/analyze/lints/s08_format_args.rs +++ b/libs/sqf/src/analyze/lints/s08_format_args.rs @@ -116,6 +116,7 @@ fn get_format_problem(input: &str, extra_args: usize) -> Option { let mut token_active = false; let mut token_start = 0; for (i, c) in format.chars().enumerate() { + let outside_token = !token_active || i > token_start; if token_active && !c.is_ascii_digit() { token_active = false; if i > token_start { @@ -133,7 +134,7 @@ fn get_format_problem(input: &str, extra_args: usize) -> Option { )); } } - if !token_active && c == '%' { + if !token_active && c == '%' && outside_token { token_active = true; token_start = i + 1; } diff --git a/libs/sqf/tests/lints/s08_format_args.sqf b/libs/sqf/tests/lints/s08_format_args.sqf index 80e31e6c..d492c023 100644 --- a/libs/sqf/tests/lints/s08_format_args.sqf +++ b/libs/sqf/tests/lints/s08_format_args.sqf @@ -7,3 +7,12 @@ format ["%1", 1, 2, 3]; // unused args format ["%1%2", 1]; // undefined tokens format ["%5", 1, 2 ,3 ,4, 5]; // skipped tokens formatText ["me too %1"]; + +format ["%1%%", 100]; +format ["%%%1%%", 100]; +format ["%%%%%%%%%%%%%%%%"]; +format ["this code is 99% bug free"]; // non-escaped +format ["%1%"]; // non-escaped (prioity over unused) +format ["%%1", 1]; // unused args +format ["%%%1", 1]; +format ["%%%1%%%2 %% %%%3%%%%", 1, 2, 3]; diff --git a/libs/sqf/tests/snapshots/lints__simple_s08_format_args.snap b/libs/sqf/tests/snapshots/lints__simple_s08_format_args.snap index 26a08d69..28b32312 100644 --- a/libs/sqf/tests/snapshots/lints__simple_s08_format_args.snap +++ b/libs/sqf/tests/snapshots/lints__simple_s08_format_args.snap @@ -35,3 +35,24 @@ expression: lint(stringify! (s08_format_args)) │ 9 │ formatText ["me too %1"]; │ ^^^^^^^^^^^^^^^^^^^^^^^ format string: undefined tokens [used "%1", passed 0] + + +error[L-S08]: format string: non-escaped "%" [at index 16] + ┌─ s08_format_args.sqf:14:1 + │ +14 │ format ["this code is 99% bug free"]; // non-escaped + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ format string: non-escaped "%" [at index 16] + + +error[L-S08]: format string: non-escaped "%" [at index 3] + ┌─ s08_format_args.sqf:15:1 + │ +15 │ format ["%1%"]; // non-escaped (prioity over unused) + │ ^^^^^^^^^^^^^ format string: non-escaped "%" [at index 3] + + +error[L-S08]: format string: unused args [used "%0", passed 1] + ┌─ s08_format_args.sqf:16:1 + │ +16 │ format ["%%1", 1]; // unused args + │ ^^^^^^^^^^^^^^^^ format string: unused args [used "%0", passed 1]