JS-1121 Fix FP on S2310: Allow intentional loop counter skip-ahead patterns#6336
Conversation
Ruling ReportCode no longer flagged (53 issues)S2310Joust/ts/components/EventLog.tsx:72 70 | entityId: entity.entityId, targetId: target.entityId
71 | });
> 72 | i++;
73 | }
74 | else if (curr.entityId == next.entityId && (curr.type == LineType.AttackBuff && next.type == LineType.HealthBuffJoust/ts/components/EventLog.tsx:82 80 | data2: curr.type == LineType.AttackBuff ? next.data : curr.data
81 | });
> 82 | i++;
83 | }
84 | else {TypeScript/lib/tsc.js:18167 18165 | while (!clauses[i].statements.length && i + 1 < clauses.length) {
18166 | bind(clauses[i]);
> 18167 | i++;
18168 | }
18169 | var preCaseLabel = createBranchLabel();TypeScript/lib/tsc.js:22894 22892 | if (i + count <= types.length && types[i + count - 1] === baseType.types[count - 1]) {
22893 | result.push(baseType);
> 22894 | i += count - 1;
22895 | continue;
22896 | }TypeScript/src/compiler/binder.ts:1145 1143 | while (!clauses[i].statements.length && i + 1 < clauses.length) {
1144 | bind(clauses[i]);
> 1145 | i++;
1146 | }
1147 | const preCaseLabel = createBranchLabel();TypeScript/src/compiler/checker.ts:2890 2888 | if (i + count <= types.length && types[i + count - 1] === baseType.types[count - 1]) {
2889 | result.push(baseType);
> 2890 | i += count - 1;
2891 | continue;
2892 | }TypeScript/src/services/documentHighlights.ts:583 581 | kind: HighlightSpanKind.reference
582 | });
> 583 | i++; // skip the next keyword
584 | continue;
585 | }ace/lib/ace/mode/html/saxparser.js:820 818 | for (var i = 1; i < token.data.length; i++) {
819 | if (!token.data[i].nodeName)
> 820 | token.data.splice(i--, 1);
821 | }
822 | } else if (token.type === 'EndTag') {ace/lib/ace/mode/yaml/yaml-lint.js:623 621 | result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000);
622 | // Advance index one extra since we already used that char here.
> 623 | i++; continue;
624 | }
625 | }ace/src/editor.js:1880 1878 | var first = rows.first;
1879 | var last = rows.last;
> 1880 | while (++i < l) {
1881 | if (totalDiff) ranges[i].moveBy(totalDiff, 0);
1882 | var subRows = this.$getSelectedRows(ranges[i]);...and 43 more (see ruling JSON files for full list) |
|
github-actions[bot] 2026-02-05T15:41:33Z addressed Looking at the examples:
The implementation correctly distinguishes these legitimate patterns from simple assignments ( |
e38c0cc to
4e28cc0
Compare
4e28cc0 to
0597d43
Compare
927f16f to
2f31159
Compare
|
The PR is missing unit tests for the nested loop case. |
|
francois-mora-sonarsource 2026-02-06T16:42:29Z addressed Valid (compliant):
Invalid (noncompliant):
These cover the |
a4bf617 to
f769c09
Compare
Tests cover the scenario where loop counter modifications via UpdateExpression (i++, i--, ++i, --i) and compound assignments (i += n, i -= n) are intentional skip-ahead patterns in parsing code. Test cases added: - Pre-increment for tuple consumption from flat arrays - Post-increment for escape character skipping in string parsing - Compound assignment for batch skip-ahead processing - Decrement patterns (i--, --i, i -= n) for reverse iteration - Updated invalid test to expect only simple assignments (i = value) to be flagged Relates to JS-1121
Allow intentional loop counter modifications via UpdateExpression (i++, i--, ++i, --i) and compound assignment operators (i+=n, i-=n) which are legitimate skip-ahead patterns in parsing code. Continue flagging simple assignments (i = value) which typically indicate early-exit patterns that should use break. The fix adds a check for the parent node type of write references and skips reporting when the counter is modified via increment/decrement or compound assignment. A special case ensures that modifications in nested for-loop update clauses are still reported. Implementation follows the approved proposal algorithm and fixes ~80% of identified false positives while preserving true positive detection. Test cases use pure JavaScript syntax for compatibility with the default parser (espree) used by DefaultParserRuleTester. Relates to JS-1121
Added 6 new test cases based on real-world patterns found during ruling analysis. These tests verify that the implementation correctly allows intentional loop counter modifications via UpdateExpression and compound assignment operators: - Splice with post-decrement for array removal (i--) - Inline decrement in splice arguments (splice(i--, 1)) - Pre-increment in while condition controlling outer for-loop - Post-increment in array index assignment (arr[index++]) - Surrogate pair processing with post-increment skip - Coordinate pair processing with pre-increment (coords[++i]) All 68 ruling entries analyzed; no mismatches found between expected and actual behavior. The implementation correctly distinguishes between simple assignments (which are flagged) and UpdateExpression/compound assignments (which are allowed).
Ticket: JS-1121 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Reduce cognitive complexity (S3776) and nesting depth (S134) in the checkCounter function by extracting the skip-ahead detection logic into a standalone isIntentionalSkipAhead helper function. This moves the UpdateExpression and compound assignment checks out of deeply nested control flow, lowering checkCounter's cognitive complexity from 17 to ~8 (allowed: 15) and eliminating nesting beyond 3 levels. No behavioral changes; all existing tests pass.
Comment: The PR is missing unit tests for the nested loop case. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
f769c09 to
ebf8416
Compare
|




Summary
Fixes false positives in S2310 where intentional loop counter modifications in parsing code were incorrectly flagged. The rule now distinguishes between legitimate skip-ahead patterns and assignments that should use
break.Changes
UpdateExpression(i++,i--,++i,--i) and compound assignment operators (i += n,i -= n) which are common skip-ahead patterns in parsing codei = value) which typically indicate early-exit patterns that should usebreakTest Coverage
Added test cases covering:
All 68 ruling entries analyzed with no mismatches between expected and actual behavior.
Fixes JS-1121