[SwiftIDEUtils] Fix infinite loop in NameMatcher for whitespace positions in string segments#3348
Open
inju2403 wants to merge 1 commit into
Conversation
…ions in string segments The `while let baseNamePosition = positionsToResolve.first(where:)` loop in the `.stringSegment` branch of `visit(_:TokenSyntax)` only mutated `positionsToResolve` via `addResolvedLocIfRequested`. When `getFirstTokenLength` returned `nil` (the position landed on whitespace inside the string segment, so the parser saw leading trivia) the loop hit `continue` without removing the position, and `first(where:)` found the same position again on every subsequent iteration -- an infinite loop. Iterate a snapshot of the matching positions instead, so a position for which `getFirstTokenLength` returns `nil` is simply skipped to the next one. This is the same class of bug as the one fixed in 528257f for the trivia loop earlier in the same function. Adds a regression test (`testStringLiteralWithPositionOnWhitespace`) that hangs against `main` and passes in <5ms with this change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes an infinite loop in
NameMatcher.visit(_:TokenSyntax)when a position inpositionsToResolvelands on whitespace inside a.stringSegmenttoken.Background
#2708 (528257f) fixed an infinite recursion in the same function for positions landing in leading/trailing trivia. The
.stringSegmentbranch of the same function uses the samewhile let first(where:)pattern but was not covered by that fix.Root cause
In the
.stringSegmentbranch:addResolvedLocIfRequestedis the only path that removes a position frompositionsToResolve. WhengetFirstTokenLengthreturnsnil— which happens when the slice begins with whitespace, becausefirstToken.leadingTriviaLengthis non-zero — the loop hitscontinuewithout removing the position.first(where:)then re-picks the same position on every subsequent iteration, causing an infinite loop.Fix
Iterate a snapshot of the matching positions, so that a position for which
getFirstTokenLengthreturnsnilis simply skipped to the next one:addResolvedLocIfRequestedstill mutatespositionsToResolveas before, so subsequent tokens see the same set as in the previous behavior — only the within-token iteration changes.Test
Adds
testStringLiteralWithPositionOnWhitespace, which hangs indefinitely againstmainand passes in <5ms with this change:(The
1️⃣marker resolves to a position that lands on the whitespace inside the string segment.)Notes
I noticed this while reviewing the
NameMatcherafter #2708 and checking whether the same antipattern existed elsewhere in the same function. I don't have a real-world reproducer beyond the test, but the failure mode, trigger condition, and fix shape are all mechanically identical to #2708, in the same file and same function.