Skip to content

Commit fa81bf5

Browse files
authored
Merge pull request #2708 from ahoppen/fix-infinite-recursion-namematcher
Fix an infinite recursion in `NameMatcher` if a position to resolve is in the leading whitespace before a token
2 parents c57764a + 528257f commit fa81bf5

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

Sources/SwiftIDEUtils/NameMatcher.swift

+18-4
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ public class NameMatcher: SyntaxAnyVisitor {
102102
return nil
103103
}
104104

105+
/// Finds the first position to resolve that is in the leading or trailing trivia of this token.
106+
///
107+
/// If one is found, also returns the range of the trivia in which the position was found.
108+
private func firstPositionToResolve(
109+
inTriviaOf token: TokenSyntax
110+
) -> (position: AbsolutePosition, triviaRange: Range<AbsolutePosition>)? {
111+
if let position = firstPositionToResolve(in: token.leadingTriviaRange) {
112+
return (position, token.leadingTriviaRange)
113+
}
114+
if let position = firstPositionToResolve(in: token.trailingTriviaRange) {
115+
return (position, token.trailingTriviaRange)
116+
}
117+
return nil
118+
}
119+
105120
// MARK: - addResolvedLocIfRequested overloads
106121

107122
/// If a position should be resolved at at the start of `baseNameRange`, create a new `DeclNameLocation` to
@@ -205,13 +220,12 @@ public class NameMatcher: SyntaxAnyVisitor {
205220
}
206221

207222
public override func visit(_ token: TokenSyntax) -> SyntaxVisitorContinueKind {
208-
while let baseNamePosition = firstPositionToResolve(in: token.leadingTriviaRange)
209-
?? firstPositionToResolve(in: token.trailingTriviaRange)
210-
{
223+
while let (baseNamePosition, triviaRange) = firstPositionToResolve(inTriviaOf: token) {
211224
// Parse the comment from the position that we want to resolve. This should parse any function calls or compound decl names, the rest of
212225
// the comment will probably be parsed as garbage but that's OK because we don't actually care about it.
213226
let positionOffsetInToken = baseNamePosition.utf8Offset - token.position.utf8Offset
214-
let commentTree = token.syntaxTextBytes[positionOffsetInToken...]
227+
let triviaRangeEndOffsetInToken = triviaRange.upperBound.utf8Offset - token.position.utf8Offset
228+
let commentTree = token.syntaxTextBytes[positionOffsetInToken..<triviaRangeEndOffsetInToken]
215229
.withUnsafeBufferPointer { (buffer) -> ExprSyntax in
216230
var parser = Parser(buffer)
217231
return ExprSyntax.parse(from: &parser)

Tests/SwiftIDEUtilsTest/NameMatcherTests.swift

+7
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,11 @@ class NameMatcherTests: XCTestCase {
381381
]
382382
)
383383
}
384+
385+
func testPositionAtSpaceInFrontOfIdentifier() {
386+
assertNameMatcherResult(
387+
" 1️⃣ fn",
388+
expected: []
389+
)
390+
}
384391
}

0 commit comments

Comments
 (0)