File tree Expand file tree Collapse file tree 2 files changed +26
-0
lines changed Expand file tree Collapse file tree 2 files changed +26
-0
lines changed Original file line number Diff line number Diff line change @@ -355,11 +355,14 @@ private struct IndexOutOfDateChecker {
355
355
356
356
private enum Error : Swift . Error , CustomStringConvertible {
357
357
case fileAttributesDontHaveModificationDate
358
+ case circularSymlink( URL )
358
359
359
360
var description : String {
360
361
switch self {
361
362
case . fileAttributesDontHaveModificationDate:
362
363
return " File attributes don't contain a modification date "
364
+ case . circularSymlink( let url) :
365
+ return " Circular symlink at \( url) "
363
366
}
364
367
}
365
368
}
@@ -517,13 +520,18 @@ private struct IndexOutOfDateChecker {
517
520
}
518
521
var modificationDate = try Self . modificationDate ( atPath: fileURL. filePath)
519
522
523
+ var visited : Set < URL > = [ fileURL]
524
+
520
525
// Get the maximum mtime in the symlink chain as the modification date of the URI. That way if either the symlink
521
526
// is changed to point to a different file or if the underlying file is modified, the modification time is
522
527
// updated.
523
528
while let relativeSymlinkDestination = try ? FileManager . default. destinationOfSymbolicLink (
524
529
atPath: fileURL. filePath
525
530
) {
526
531
fileURL = URL ( fileURLWithPath: relativeSymlinkDestination, relativeTo: fileURL)
532
+ if !visited. insert ( fileURL) . inserted {
533
+ throw Error . circularSymlink ( fileURL)
534
+ }
527
535
modificationDate = max ( modificationDate, try Self . modificationDate ( atPath: fileURL. filePath) )
528
536
}
529
537
Original file line number Diff line number Diff line change @@ -2521,6 +2521,24 @@ final class BackgroundIndexingTests: XCTestCase {
2521
2521
let workspaceSymbolsAfterUpdate = try await project. testClient. send ( WorkspaceSymbolsRequest ( query: " myTest " ) )
2522
2522
XCTAssertEqual ( workspaceSymbolsAfterUpdate? . compactMap ( \. symbolInformation? . name) , [ " myTestA_updated " , " myTestB " ] )
2523
2523
}
2524
+
2525
+ func testCircularSymlink( ) async throws {
2526
+ let project = try await SwiftPMTestProject (
2527
+ files: [
2528
+ " Symlink.swift " : " "
2529
+ ] ,
2530
+ enableBackgroundIndexing: true
2531
+ )
2532
+ let circularSymlink = try XCTUnwrap ( project. uri ( for: " Symlink.swift " ) . fileURL)
2533
+ try FileManager . default. removeItem ( at: circularSymlink)
2534
+ try FileManager . default. createSymbolicLink ( at: circularSymlink, withDestinationURL: circularSymlink)
2535
+
2536
+ project. testClient. send (
2537
+ DidChangeWatchedFilesNotification ( changes: [ FileEvent ( uri: URI ( circularSymlink) , type: . changed) ] )
2538
+ )
2539
+ // Check that we don't enter an infinite loop trying to index the circular symlink.
2540
+ try await project. testClient. send ( SynchronizeRequest ( index: true ) )
2541
+ }
2524
2542
}
2525
2543
2526
2544
extension HoverResponseContents {
You can’t perform that action at this time.
0 commit comments