Skip to content

Commit 7aed63b

Browse files
authored
Merge pull request #2899 from ahoppen/conflict-marker-infinite-loop
Fix an infinite loop if a conflict marker is found but it's not at the start of a new line
2 parents 1cd3534 + d724f5e commit 7aed63b

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

Sources/SwiftParser/Lexer/Cursor.swift

+21-15
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ extension Lexer {
292292
self.stateStack.perform(stateTransition: stateTransition, stateAllocator: stateAllocator)
293293
}
294294

295-
func starts(with possiblePrefix: some Sequence<UInt8>) -> Bool {
295+
func starts(with possiblePrefix: SyntaxText) -> Bool {
296296
return self.input.starts(with: possiblePrefix)
297297
}
298298

@@ -2036,7 +2036,7 @@ extension Lexer.Cursor {
20362036
}
20372037

20382038
// Special case; allow '`$`'.
2039-
if quote.starts(with: "`$`".utf8) {
2039+
if quote.starts(with: "`$`") {
20402040
self = quote
20412041
let firstBacktickConsumed = self.advance(matching: "`")
20422042
let dollarConsumed = self.advance(matching: "$")
@@ -2383,7 +2383,7 @@ extension Lexer.Cursor {
23832383
case normal
23842384
case perforce
23852385

2386-
var introducer: String {
2386+
var introducer: SyntaxText {
23872387
switch self {
23882388
case .perforce:
23892389
return ">>>> "
@@ -2392,7 +2392,7 @@ extension Lexer.Cursor {
23922392
}
23932393
}
23942394

2395-
var terminator: String {
2395+
var terminator: SyntaxText {
23962396
switch self {
23972397
case .perforce:
23982398
return "<<<<\n"
@@ -2408,11 +2408,15 @@ extension Lexer.Cursor {
24082408
}
24092409

24102410
// Check to see if we have <<<<<<< or >>>>.
2411-
guard start.starts(with: "<<<<<<< ".utf8) || start.starts(with: ">>>> ".utf8) else {
2411+
let kind: ConflictMarker
2412+
if start.starts(with: ConflictMarker.normal.introducer) {
2413+
kind = .normal
2414+
} else if start.starts(with: ConflictMarker.perforce.introducer) {
2415+
kind = .perforce
2416+
} else {
24122417
return false
24132418
}
24142419

2415-
let kind = start.is(at: "<") ? ConflictMarker.normal : .perforce
24162420
guard let end = Self.findConflictEnd(start, markerKind: kind) else {
24172421
// No end of conflict marker found.
24182422
return false
@@ -2432,29 +2436,31 @@ extension Lexer.Cursor {
24322436
static func findConflictEnd(_ curPtr: Lexer.Cursor, markerKind: ConflictMarker) -> Lexer.Cursor? {
24332437
// Get a reference to the rest of the buffer minus the length of the start
24342438
// of the conflict marker.
2435-
let advanced = curPtr.input.baseAddress?.advanced(by: markerKind.introducer.utf8.count)
2439+
let advanced = curPtr.input.baseAddress?.advanced(by: markerKind.introducer.count)
24362440
var restOfBuffer = Lexer.Cursor(
2437-
input: .init(start: advanced, count: curPtr.input.count - markerKind.introducer.utf8.count),
2438-
previous: curPtr.input[markerKind.introducer.utf8.count - 1]
2441+
input: .init(start: advanced, count: curPtr.input.count - markerKind.introducer.count),
2442+
previous: curPtr.input[markerKind.introducer.count - 1]
24392443
)
2444+
let terminator = markerKind.terminator
2445+
let terminatorStart = terminator.first!
24402446
while !restOfBuffer.isAtEndOfFile {
2441-
let terminatorStart = markerKind.terminator.unicodeScalars.first!
2442-
restOfBuffer.advance(while: { byte in byte != terminatorStart })
2447+
restOfBuffer.advance(while: { $0.value != terminatorStart })
24432448

2444-
guard restOfBuffer.starts(with: markerKind.terminator.utf8) else {
2449+
guard restOfBuffer.starts(with: terminator) else {
24452450
_ = restOfBuffer.advance()
24462451
continue
24472452
}
24482453

24492454
// Must occur at start of line.
24502455
guard restOfBuffer.previous == "\n" || restOfBuffer.previous == "\r" else {
2456+
_ = restOfBuffer.advance()
24512457
continue
24522458
}
24532459

2454-
let advanced = restOfBuffer.input.baseAddress?.advanced(by: markerKind.terminator.utf8.count)
2460+
let advanced = restOfBuffer.input.baseAddress?.advanced(by: terminator.count)
24552461
return Lexer.Cursor(
2456-
input: .init(start: advanced, count: restOfBuffer.input.count - markerKind.terminator.utf8.count),
2457-
previous: restOfBuffer.input[markerKind.terminator.utf8.count - 1]
2462+
input: .init(start: advanced, count: restOfBuffer.input.count - terminator.count),
2463+
previous: restOfBuffer.input[terminator.count - 1]
24582464
)
24592465
}
24602466
return nil

Tests/SwiftParserTest/LexerTests.swift

+15
Original file line numberDiff line numberDiff line change
@@ -1706,4 +1706,19 @@ class LexerTests: ParserTestCase {
17061706
]
17071707
)
17081708
}
1709+
1710+
func testConflictMarkerNotAtStartOfLine() {
1711+
assertLexemes(
1712+
#"""
1713+
<<<<<<< a
1714+
>>>>>>> a
1715+
"""#,
1716+
lexemes: [
1717+
LexemeSpec(.binaryOperator, text: "<<<<<<<", trailing: " "),
1718+
LexemeSpec(.identifier, text: "a"),
1719+
LexemeSpec(.binaryOperator, leading: "\n ", text: ">>>>>>>", trailing: " ", flags: [.isAtStartOfLine]),
1720+
LexemeSpec(.identifier, text: "a"),
1721+
]
1722+
)
1723+
}
17091724
}

0 commit comments

Comments
 (0)