Skip to content

[source_span] Fix CR/CRLF highlighting, point-span context, and subspan - #2634

Merged
kevmoo merged 7 commits into
mainfrom
fix-source_span
Oct 27, 2026
Merged

kevmoo merged 7 commits into
mainfrom
fix-source_span

Conversation

@kevmoo

@kevmoo kevmoo commented Oct 3, 2026 •

Copy link
Copy Markdown
Member
  • Normalize bare \r and \r\n line endings in Highlighter, findLineStart, and subspanLocations (preventing a RangeError when highlighting spans ending at a bare \r, disambiguating multi-line SourceSpanWithContext subspans via span location metadata, and fixing subspan(span.length) on spans ending with the \r of a \r\n sequence).
  • Fix FileSpan.context returning '' for point spans at column 0 of the last line in a multi-line file without a trailing newline.
  • Fix _Highlight._normalizeEndOfLine column calculation when start.column > 0 and simplify _Highlight._lastLineLength to fix off-by-one column calculation on plain spans ending with \n\n.
  • Align _FileSpan.== and _FileSpan.hashCode with SourceSpan without allocating FileLocations, and remove unreachable code in SourceFile.getLine, _FileSpan.subspan, SourceLocation, _Highlight._normalizeTrailingNewline, and subspanLocations.

* Normalize bare `\r` and `\r\n` line endings in `Highlighter`, `findLineStart`,
  and `subspanLocations` (fixes `SPAN-1` `RangeError` and `subspan` at end of
  spans ending with `\r` of `\r\n`).
* Fix `FileSpan.context` returning `''` for point spans at column 0 of the last
  line in a multi-line file without a trailing newline (`SPAN-2`).
* Fix `_Highlight._normalizeEndOfLine` column calculation when `start.column > 0`
  and simplify `_Highlight._lastLineLength` to fix off-by-one on plain spans
  ending with `\n\n`.
* Remove unreachable code in `SourceFile.getLine`, `_FileSpan.subspan`,
  `SourceLocation`, `_Highlight._normalizeTrailingNewline`, and
  `subspanLocations`, and avoid allocating `FileLocation`s in `_FileSpan.==`.
@kevmoo
kevmoo requested a review from a team as a code owner October 3, 2026 16:53
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

PR Health

Coverage ⚠️
File Coverage
pkgs/source_span/lib/src/file.dart 💚 91 % ⬆️ 3 %
pkgs/source_span/lib/src/highlighter.dart 💚 97 % ⬆️ 1 %
pkgs/source_span/lib/src/location.dart 💚 97 %
pkgs/source_span/lib/src/span_with_context.dart 💔 91 % ⬇️ 9 %
pkgs/source_span/lib/src/utils.dart 💚 99 % ⬆️ 2 %

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

License Headers ✔️
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/html/test/differential_test.dart
pkgs/html/test/dom_parsing_test.dart
pkgs/html/test/mxss_test.dart
pkgs/html/test/noah_ark_clause_limit_test.dart

This check can be disabled by tagging the PR with skip-license-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
source_span None 1.10.2 1.10.3-wip 1.10.3-wip ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

Unused Dependencies ✔️
Package Status
source_span ✔️ All dependencies utilized correctly.

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check (for example, for non-user-visible changes when the package version is already at -wip).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses several bugs in the source_span package, particularly fixing RangeError and assertion failures when highlighting or slicing spans with bare \r or \r\n line endings, and resolving an issue where FileSpan.context returned an empty string for point spans at the start of the last line in files without trailing newlines. The changes refactor newline detection and normalization across file.dart, highlighter.dart, and utils.dart, and add corresponding tests. The review feedback highlights a critical issue in the updated == operator for _FileSpan, which omits the text comparison when compared to a SourceSpan, potentially leading to asymmetric equality behavior.

Comment thread pkgs/source_span/lib/src/file.dart Resolved
@kevmoo
kevmoo requested a review from natebosch October 19, 2026 14:48
@davidmorgan
davidmorgan self-requested a review October 22, 2026 05:01

@davidmorgan davidmorgan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this: the CR handling is a big improvement. I fuzzed every string of up to 5 characters over a, b, \r and \n, and every span in each, as a file span, a span with context and a plain span. highlight(), context and subspan go from 2078 throws and 2247 wrong subspan locations on main to none on this PR. With bare CRs, the highlight output is the same as for the file with LF endings.

Two regressions turn up when you highlight a SourceSpanWithContext subspan that keeps its parent's multi-line context. Both are in the inline comments:

SourceSpanWithContext ctx(String s) {
  final f = SourceFile.fromString(s).span(0, s.length);
  return SourceSpanWithContext(f.start, f.end, f.text, f.context);
}
ctx('ab\r\nabba').subspan(3, 3).highlight(); // main: line 1, caret at col 3. PR: labels `0 | ab`, caret on `abba`.
ctx('a\rb\r\n').subspan(3, 4).highlight();   // main: no throw. PR: RangeError (end).

This existing bug isn't caused by the PR, but it is nearby: ctx('b\r\nb\r').subspan(4, 5).highlight() throws on main as well, and on this PR with a different message.

Also existing: a _FileSpan and a SourceSpan with the same offsets and URL compare equal but have different hashCodes, because one hashes (_start, _end, sourceUrl) and the other the two SourceLocations. The new symmetric-equality test pins that equality without checking hashCode.

Comment thread pkgs/source_span/lib/src/utils.dart Resolved
Comment thread pkgs/source_span/test/span_test.dart Resolved
…n.hashCode

* Restore `findLineStart` empty-text CRLF matching on the line containing `\r\n`.
* Add `findSpanLineStart` to locate `SourceSpanWithContext` spans once using end-location and start-line/offset metadata, storing `linesBeforeSpan` on `_Highlight` and preserving trailing empty lines for point spans.
* Align `_FileSpan.hashCode` with `SourceSpanMixin.hashCode` (`Object.hash(start, end)`) when comparing equal.
* Add explicit `line`/`column` subspan assertions, 4-char `SourceSpanWithContext` subspan highlight fuzz tests, and clean up internal tracker labels in `highlight_test.dart`.
@kevmoo

kevmoo commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

Thanks for the fuzzing sweep! Addressed all inline comments plus the b\r\nb\r subspan case and _FileSpan.hashCode parity in e0926f8 — PTAL.

@kevmoo
kevmoo requested a review from davidmorgan October 22, 2026 15:53
Comment thread pkgs/source_span/CHANGELOG.md Resolved
Comment thread pkgs/source_span/lib/src/utils.dart Resolved
@kevmoo

kevmoo commented Oct 23, 2026

Copy link
Copy Markdown
Member Author

Addressed both comments: stripped CR from effectiveLineEnd and removed absolute offset checks entirely (which fixes the heuristic while making the flawed tests obsolete, so they are skipped/removed). PTAL.

@kevmoo
kevmoo requested a review from davidmorgan October 23, 2026 17:15
…ontext

* Add an internal `SubspanWithContext` subclass in `lib/src/utils.dart` so
  `SourceSpanWithContextExtension.subspan` preserves the exact code-unit start
  offset within `context` without `Expando` state or heuristic line scoring.
* Resolve `SubspanWithContext` line starts directly in `findSpanLineStart` and
  match `SourceSpanWithContext` candidates by column, text, and end location.
* Enable all tests in `test/utils_test.dart` and `test/highlight_test.dart` and
  add multi-line duplicate-line, CRLF, and exhaustive 4-char CR/LF subspan
  coverage.
* Delegate the non-`SubspanWithContext` fallback in `findSpanLineStart` to
  `findLineStart` and remove the redundant `_matchesEndLocation` line scan.
* Reuse `_isLineEnd` in `subspanLocations` to avoid duplicating CR/LF line-end
  checks.
@kevmoo
kevmoo merged commit d5c2102 into main Oct 27, 2026
22 checks passed
@kevmoo
kevmoo deleted the fix-source_span branch October 27, 2026 22:07
copybara-service Bot pushed a commit to dart-lang/sdk that referenced this pull request Oct 28, 2026
…est, tools, webkit_inspection_protocol

Revisions updated by `dart tools/rev_sdk_deps.dart`.

core (https://github.com/dart-lang/core/compare/04da676..d7bd45c):
  d7bd45c1  Wed Oct 28 13:23:54 2026 +0530  Chandra ObulaReddy  [args] Wrap separators to usageLineLength (dart-lang/core#1032)
  6903c6c7  Fri Oct 23 20:10:24 2026 +0000  Jonas Finnemann Jensen  [crypto] Prepare to publish 3.0.8 (dart-lang/core#1026)
  7c1c3700  Fri Oct 23 11:14:15 2026 -0700  Kevin Moore  Tighten pull_request_label workflow permissions (dart-lang/core#1029)
  f01024fc  Thu Oct 22 16:31:50 2026 -0700  Kevin Moore  [collection] Share Iterable and Set tests across wrapper_test.dart (dart-lang/core#1028)
  c782eab4  Thu Oct 22 13:25:34 2026 +0200  Jonas Finnemann Jensen  Update convert package README and add examples (dart-lang/core#999)

dartdoc (https://github.com/dart-lang/dartdoc/compare/c0e19cf..db94437):
  db94437c  Wed Oct 28 11:37:17 2026 +0100  Sarah Zakarias   Add the doc-reference-target-differs warning (dart-lang/dartdoc#4306)
  b6e3980c  Tue Oct 27 14:59:21 2026 +0100  Sarah Zakarias  Only treat a doc comment as library documentation when it precedes a library directive (dart-lang/dartdoc#4303)
  84a0141f  Tue Oct 27 11:22:04 2026 +0100  Sarah Zakarias  Add the unscoped-doc-reference warning (dart-lang/dartdoc#4305)
  b25bcd99  Thu Oct 22 15:56:17 2026 +0300  Sergey G. Grekhov  Update/replace TODO in co19 tests (dart-lang/dartdoc#4299)
  1e9e771e  Thu Oct 22 12:18:48 2026 +0300  Sergey G. Grekhov  `#4134`. Add more placement tests for `library` directives (dart-lang/dartdoc#4297)
  17629ced  Wed Oct 21 10:29:05 2026 -0700  Bob Nystrom  Use newer function type syntax for parameters. (dart-lang/dartdoc#4290)
  f5928b1d  Wed Oct 21 15:44:39 2026 +0300  Sergey G. Grekhov  `#4134`. Add placement tests for enum values (dart-lang/dartdoc#4223)
  24ae37f3  Wed Oct 21 11:18:07 2026 +0200  dependabot[bot]  Bump test_reflective_loader from 0.4.0 to 0.6.0 (dart-lang/dartdoc#4296)

ecosystem (https://github.com/dart-lang/ecosystem/compare/0ab0cfd..24b9ba8):
  24b9ba8  Mon Oct 26 18:40:19 2026 -0700  Kevin Moore  fix(repo_manage): increment patch version when transitioning to -wip (dart-lang/ecosystem#474)
  e1d4a04  Fri Oct 23 20:18:20 2026 +0000  dependabot[bot]  Bump the github-actions group across 1 directory with 8 updates (dart-lang/ecosystem#473)
  4b44357  Fri Oct 23 11:13:26 2026 -0700  Kevin Moore  Tighten pull_request_label workflow permissions (dart-lang/ecosystem#472)

i18n (https://github.com/dart-lang/i18n/compare/1f5ea2f..4c7b4ad):
  4c7b4ad1  Fri Oct 23 11:14:00 2026 -0700  Kevin Moore  Tighten pull_request_label workflow permissions (dart-lang/i18n#1113)
  899251b1  Thu Oct 8 11:30:18 2026 +0200  Moritz  [intl4x] Fix doc comment examples and verify them via {@example} in tests (dart-lang/i18n#1107)
  5c8eb9d5  Thu Oct 8 10:27:58 2026 +0200  Moritz  [intl4x] Fix YearStyle.withEra on ECMA when length is short or omitted (dart-lang/i18n#1105)
  b80bb04a  Wed Sep 23 14:37:42 2026 +0200  Michael Thomsen  Remove experiment flag no longer needed (dart-lang/i18n#1097)
  766fd507  Wed Sep 23 13:59:56 2026 +0200  Moritz  [intl4x] Mark DisplayNames API as @experimental and trigger CI on PR base edits (dart-lang/i18n#1098)
  08de2f6f  Fri Sep 18 12:49:50 2026 +0200  Moritz  Rev package:intl4x to 1.0.0 and update status to preview (dart-lang/i18n#1088)

native (https://github.com/dart-lang/native/compare/3cbe319..e0ca7c6):
  e0ca7c60f  Wed Oct 28 12:08:25 2026 +0100  Michael Goderbauer  [infra] Pin ubuntu-24.04 in workflows installing clang-15 (dart-lang/native#3771)
  eb09430a9  Tue Oct 27 10:43:22 2026 +0100  Michael Goderbauer  [jni] Publish v1.1.1 (dart-lang/native#3765)
  94b5f4337  Tue Oct 27 10:21:16 2026 +0100  Michael Goderbauer  [jnigen] Pin ubuntu-24.04 in CI workflow (dart-lang/native#3766)
  74cc078ee  Tue Oct 27 09:29:23 2026 +0100  Michael Goderbauer  [jni] Add ProGuard consumer rules for Kotlin classes used by suspend functions (dart-lang/native#3756)
  0aa672fed  Fri Oct 23 11:13:43 2026 -0700  Kevin Moore  [infra] Tighten pull_request_label workflow permissions (dart-lang/native#3764)
  8b11b6e01  Fri Oct 23 13:38:47 2026 +0200  Michael Goderbauer  [jnigen] Bump AGP to 9.1.1 and KGP to 2.4.10 for Flutter beta (dart-lang/native#3758)

protobuf (https://github.com/dart-lang/protobuf/compare/a73edc9..1d52301):
  1d52301  Wed Oct 28 08:18:02 2026 -0700  Kevin Moore  test(protoc_plugin): replace dart:mirrors in reserved_names_test (google/protobuf.dart#1104)

shelf (https://github.com/dart-lang/shelf/compare/b66665b..73b2382):
  73b2382  Thu Oct 22 10:43:29 2026 -0700  Kevin Moore  shelf_router_generator: ignore invalid_use_of_internal_member on RouterEntry (dart-lang/shelf#548)

shelf is held back at 73b2382, before dart-lang/shelf#547, because
`pkgs/shelf/test/shelf_io_test.dart` now imports the unpublished
`package:_shelf_compliance`, which breaks the shared `shelf_tests` target in
google3.

test (https://github.com/dart-lang/test/compare/d1afeb1..5967927):
  5967927e  Mon Oct 26 17:50:52 2026 -0700  Nate Bosch  Diagnose browser connection failures and time them out with the suite load timeout (dart-lang/test#2788)
  0692e8ae  Mon Oct 26 16:29:27 2026 -0700  Kevin Moore  Remove mirror_matchers.dart from package:matcher (dart-lang/test#2802)
  da21f85a  Fri Oct 23 11:13:38 2026 -0700  Kevin Moore  Tighten pull_request_label workflow permissions (dart-lang/test#2804)
  e18fd112  Thu Oct 22 15:38:51 2026 -0700  Nate Bosch  Report tests that pass on retry as flaky (dart-lang/test#2801)
  b4ef80c0  Fri Oct 23 02:44:25 2026 +0600  Pranta Dutta  Fix compact reporter crash when the terminal is too narrow (dart-lang/test#2799)
  e3a7f2b6  Tue Oct 20 15:51:34 2026 -0700  Nate Bosch  Check that web entrypoints don't import VM-only libraries (dart-lang/test#2797)

tools (https://github.com/dart-lang/tools/compare/eee87b1..3980dca):
  3980dca39  Wed Oct 28 11:43:38 2026 +0100  Jonas Finnemann Jensen  [html] Move contributors list from LICENSE to AUTHORS (dart-lang/tools#2733)
  2866a7745  Wed Oct 28 11:13:19 2026 +0100  Jonas Finnemann Jensen  [extension_discovery] Prepare for v2.1.1 release (dart-lang/tools#2727)
  530feb74e  Wed Oct 28 13:38:07 2026 +0530  Chandra ObulaReddy  [csslib] Fix the aliceblue, antiquewhite and peru color values (dart-lang/tools#2732)
  d5c210271  Tue Oct 27 15:07:32 2026 -0700  Kevin Moore  [source_span] Fix CR/CRLF highlighting, point-span context, and subspan (dart-lang/tools#2634)
  cbea5b08e  Tue Oct 27 15:07:27 2026 -0700  Kevin Moore  [string_scanner] Validate error() span bounds and test eager lastSpan (dart-lang/tools#2715)
  22fd7a6a8  Tue Oct 27 15:07:20 2026 -0700  Kevin Moore  [csslib] Fix parser, analyzer, polyfill, and printer crashes (dart-lang/tools#2638)

webkit_inspection_protocol (https://github.com/google/webkit_inspection_protocol.dart/compare/762115a..2c255f2):
  2c255f2  Thu Oct 22 14:18:44 2026 -0700  Kevin Moore  Remove dart:mirrors and deprecate dom_model.dart and forwarder.dart (google/webkit_inspection_protocol.dart#141)

web is held back at 4e60e61, before dart-lang/web#596, because it changes
`package:web` signatures (e.g. `innerHTML=`, `parseFromString`, `Worker()`)
from `JSAny` to `String` in ways that break callers in google3.

Change-Id: Ia4253b35a91d7c05e34fe0e150ea4cb3e6628015
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/569660
Commit-Queue: Nate Bosch <[email protected]>
Reviewed-by: Brian Quinlan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants