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