Skip to content

Fix line numbering for non-standard line separators - #52

Merged
mevichitra merged 1 commit into
mainfrom
claude/sweet-edison-xn7t27
Oct 14, 2026
Merged

mevichitra merged 1 commit into
mainfrom
claude/sweet-edison-xn7t27

Conversation

@mevichitra

Copy link
Copy Markdown
Owner

Summary

Source code is now split into lines using only LF (\n), CRLF (\r\n), and CR (\r) as line separators, matching how Python's ast module and tree-sitter number lines. Previously, other Unicode line breaks (form feed \x0c, vertical tab \x0b, \x85, U+2028, U+2029, etc.) were treated as line separators, causing all subsequent line numbers to be shifted. This led to incorrect fingerprints, failed suppression comments, and misaligned editor positions for findings after such characters.

Type of change

  • Bug fix (false positive / false negative correction)
  • Engine / runner change

Changes

  • Added split_lines() function in new src/codeguard/engine/text.py that splits source text on standard line separators only
  • Updated all line-splitting logic across the codebase to use split_lines() instead of str.splitlines():
    • fingerprint.py: fingerprint calculation
    • suppressions.py: parsing inline suppression comments
    • context.py: caching source lines for rule context
    • dataflow/python.py: taint analysis
    • lsp/positions.py: LSP position conversion
    • rules/security/cg_sec_009_insecure_random.py: import insertion logic
  • Added comprehensive tests for line separator handling in tests/test_engine/test_fingerprint.py and new tests/test_engine/test_text.py
  • Added regression tests in tests/test_engine/test_suppressions.py and tests/test_lsp/test_positions.py

Checklist

  • git commit -s — DCO sign-off on all commits
  • pytest passes locally
  • ruff check src/ tests/ clean
  • mypy src/ clean
  • News fragment added in changelog.d/

Test evidence

New test classes added:

  • TestLineSeparators in test_fingerprint.py: Tests that form feeds and other Unicode line breaks don't shift line numbers or affect fingerprints
  • TestLineSeparators.test_finding_after_form_feed_uses_its_own_line: Verifies findings after form feeds get correct line numbers
  • TestLineSeparators.test_unicode_line_breaks_do_not_shift_lines: Parametrized test for various Unicode line breaks
  • TestLineSeparators.test_crlf_and_cr_line_endings: Tests CRLF and CR line ending handling
  • test_text.py: Comprehensive tests for split_lines() function matching str.splitlines() behavior on standard separators
  • test_suppressions.py: Tests that form feeds don't affect suppression comment parsing
  • test_positions.py: Tests that LSP position conversion handles non-standard line breaks correctly

Notes for reviewer

The key insight is that Python's ast module and tree-sitter only count LF, CRLF, and CR as line separators when numbering lines. Using str.splitlines() was incorrect because it treats many other Unicode characters as line breaks. The new split_lines() function ensures consistent line numbering across fingerprinting, suppression parsing, and position conversion.

https://claude.ai/code/session_018woih8gNc6h8GSJVjbAixU

str.splitlines() also breaks on form feed, vertical tab, \x1c-\x1e, \x85,
U+2028 and U+2029, which ast and tree-sitter do not count as line ends.
In a file containing one of them, every later finding was fingerprinted
from the wrong line, inline suppressions after it attached to the wrong
line, and LSP ranges were off.

Add engine.text.split_lines and use it wherever source is indexed by
line number: fingerprints, RuleContext.lines, dataflow snippets,
suppression parsing, CG-SEC-009's import insertion and the LSP LineIndex
(which now also handles CR-only documents).
@mevichitra
mevichitra merged commit 1d49bf9 into main Oct 14, 2026
18 checks passed
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