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 {
355355
356356 private enum Error : Swift . Error , CustomStringConvertible {
357357 case fileAttributesDontHaveModificationDate
358+ case circularSymlink( URL )
358359
359360 var description : String {
360361 switch self {
361362 case . fileAttributesDontHaveModificationDate:
362363 return " File attributes don't contain a modification date "
364+ case . circularSymlink( let url) :
365+ return " Circular symlink at \( url) "
363366 }
364367 }
365368 }
@@ -517,13 +520,18 @@ private struct IndexOutOfDateChecker {
517520 }
518521 var modificationDate = try Self . modificationDate ( atPath: fileURL. filePath)
519522
523+ var visited : Set < URL > = [ fileURL]
524+
520525 // Get the maximum mtime in the symlink chain as the modification date of the URI. That way if either the symlink
521526 // is changed to point to a different file or if the underlying file is modified, the modification time is
522527 // updated.
523528 while let relativeSymlinkDestination = try ? FileManager . default. destinationOfSymbolicLink (
524529 atPath: fileURL. filePath
525530 ) {
526531 fileURL = URL ( fileURLWithPath: relativeSymlinkDestination, relativeTo: fileURL)
532+ if !visited. insert ( fileURL) . inserted {
533+ throw Error . circularSymlink ( fileURL)
534+ }
527535 modificationDate = max ( modificationDate, try Self . modificationDate ( atPath: fileURL. filePath) )
528536 }
529537
Original file line number Diff line number Diff line change @@ -2521,6 +2521,24 @@ final class BackgroundIndexingTests: XCTestCase {
25212521 let workspaceSymbolsAfterUpdate = try await project. testClient. send ( WorkspaceSymbolsRequest ( query: " myTest " ) )
25222522 XCTAssertEqual ( workspaceSymbolsAfterUpdate? . compactMap ( \. symbolInformation? . name) , [ " myTestA_updated " , " myTestB " ] )
25232523 }
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+ }
25242542}
25252543
25262544extension HoverResponseContents {
You can’t perform that action at this time.
0 commit comments