diff --git a/Sources/BuildSystemIntegration/CompilationDatabase.swift b/Sources/BuildSystemIntegration/CompilationDatabase.swift index 817b893b..91037ce7 100644 --- a/Sources/BuildSystemIntegration/CompilationDatabase.swift +++ b/Sources/BuildSystemIntegration/CompilationDatabase.swift @@ -34,6 +34,10 @@ import struct TSCBasic.RelativePath import var TSCBasic.localFileSystem #endif +#if os(Windows) +import WinSDK +#endif + /// A single compilation database command. /// /// See https://clang.llvm.org/docs/JSONCompilationDatabase.html @@ -97,7 +101,7 @@ package struct CompilationDatabaseCompileCommand: Equatable, Codable { /// it falls back to `filename`, which is more likely to be the identifier /// that a caller will be looking for. package var uri: DocumentURI { - if filename.hasPrefix("/") || !directory.hasPrefix("/") { + if filename.isAbsolutePath || !directory.isAbsolutePath { return DocumentURI(filePath: filename, isDirectory: false) } else { return DocumentURI(URL(fileURLWithPath: directory).appendingPathComponent(filename, isDirectory: false)) @@ -288,3 +292,15 @@ enum CompilationDatabaseDecodingError: Error { case missingCommandOrArguments case fixedDatabaseDecodingError } + +fileprivate extension String { + var isAbsolutePath: Bool { + #if os(Windows) + Array(self.utf16).withUnsafeBufferPointer { buffer in + return !PathIsRelativeW(buffer.baseAddress) + } + #else + return self.hasPrefix("/") + #endif + } +} diff --git a/Sources/SKSupport/DocumentURI+symlinkTarget.swift b/Sources/SKSupport/DocumentURI+symlinkTarget.swift index 083c4e63..34a15df6 100644 --- a/Sources/SKSupport/DocumentURI+symlinkTarget.swift +++ b/Sources/SKSupport/DocumentURI+symlinkTarget.swift @@ -27,10 +27,10 @@ extension DocumentURI { guard let fileUrl = fileURL else { return nil } - let realpath = fileUrl.realpath - if realpath == fileURL { + let realpath = DocumentURI(fileUrl.realpath) + if realpath == self { return nil } - return DocumentURI(realpath) + return realpath } } diff --git a/Sources/SKTestSupport/BuildServerTestProject.swift b/Sources/SKTestSupport/BuildServerTestProject.swift index 43c1ae4f..fc50c149 100644 --- a/Sources/SKTestSupport/BuildServerTestProject.swift +++ b/Sources/SKTestSupport/BuildServerTestProject.swift @@ -17,7 +17,7 @@ import XCTest fileprivate let sdkArgs = if let defaultSDKPath { """ - "-sdk", "\(defaultSDKPath)", + "-sdk", "\(defaultSDKPath.replacing(#"\"#, with: #"\\"#))", """ } else { "" diff --git a/Sources/SKTestSupport/FindTool.swift b/Sources/SKTestSupport/FindTool.swift index 0f6207e4..d134e715 100644 --- a/Sources/SKTestSupport/FindTool.swift +++ b/Sources/SKTestSupport/FindTool.swift @@ -48,8 +48,14 @@ package func findTool(name: String) async -> URL? { return nil } #if os(Windows) - path = String((path.split { $0.isNewline })[0]) + // where.exe returns all files that match the name. We only care about the first one. + if let newlineIndex = path.firstIndex(where: \.isNewline) { + path = String(path[.. URL { if let firstDash = uuid.firstIndex(of: "-") { uuid = uuid[.. [CodeAction], + testName: String = #function, file: StaticString = #filePath, line: UInt = #line ) async throws { let testClient = try await TestSourceKitLSPClient(capabilities: clientCapabilitiesWithCodeActionSupport) - let uri = DocumentURI(for: .swift) + let uri = DocumentURI(for: .swift, testName: testName) let positions = testClient.openDocument(markedText, uri: uri) var ranges = ranges diff --git a/Tests/SourceKitLSPTests/IndexTests.swift b/Tests/SourceKitLSPTests/IndexTests.swift index 7960b17e..89e57ea6 100644 --- a/Tests/SourceKitLSPTests/IndexTests.swift +++ b/Tests/SourceKitLSPTests/IndexTests.swift @@ -99,6 +99,10 @@ final class IndexTests: XCTestCase { } func testIndexShutdown() async throws { + #if os(Windows) + // TODO: Fix this test (https://github.com/swiftlang/sourcekit-lsp/issues/1750) + try XCTSkipIf(true, "https://github.com/swiftlang/sourcekit-lsp/issues/1750") + #endif func listdir(_ url: URL) throws -> [URL] { try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) diff --git a/Tests/SourceKitLSPTests/LocalClangTests.swift b/Tests/SourceKitLSPTests/LocalClangTests.swift index f6b36d08..d89dcd93 100644 --- a/Tests/SourceKitLSPTests/LocalClangTests.swift +++ b/Tests/SourceKitLSPTests/LocalClangTests.swift @@ -245,6 +245,10 @@ final class LocalClangTests: XCTestCase { } func testClangModules() async throws { + #if os(Windows) + // TODO: Enable this test once https://github.com/swiftlang/swift-foundation/issues/973 is fixed + try XCTSkipIf(true, "https://github.com/swiftlang/swift-foundation/issues/973") + #endif let project = try await MultiFileTestProject( files: [ "ClangModuleA.h": """ diff --git a/Tests/SourceKitLSPTests/SwiftInterfaceTests.swift b/Tests/SourceKitLSPTests/SwiftInterfaceTests.swift index c898d808..fce7ae9f 100644 --- a/Tests/SourceKitLSPTests/SwiftInterfaceTests.swift +++ b/Tests/SourceKitLSPTests/SwiftInterfaceTests.swift @@ -65,7 +65,7 @@ final class SwiftInterfaceTests: XCTestCase { uri: project.fileURI, position: project.positions["1️⃣"], testClient: project.testClient, - swiftInterfaceFile: "/Swift.String.swiftinterface", + swiftInterfaceFile: "Swift.String.swiftinterface", linePrefix: "@frozen public struct String" ) // Test stdlib with two submodules @@ -73,7 +73,7 @@ final class SwiftInterfaceTests: XCTestCase { uri: project.fileURI, position: project.positions["2️⃣"], testClient: project.testClient, - swiftInterfaceFile: "/Swift.Math.Integers.swiftinterface", + swiftInterfaceFile: "Swift.Math.Integers.swiftinterface", linePrefix: "@frozen public struct Int" ) // Test concurrency @@ -81,7 +81,7 @@ final class SwiftInterfaceTests: XCTestCase { uri: project.fileURI, position: project.positions["3️⃣"], testClient: project.testClient, - swiftInterfaceFile: "/_Concurrency.swiftinterface", + swiftInterfaceFile: "_Concurrency.swiftinterface", linePrefix: "@inlinable public func withTaskGroup" ) } @@ -118,7 +118,7 @@ final class SwiftInterfaceTests: XCTestCase { ) ) let location = try XCTUnwrap(response?.locations?.only) - XCTAssertTrue(location.uri.pseudoPath.hasSuffix("/MyLibrary.swiftinterface")) + XCTAssertTrue(location.uri.pseudoPath.hasSuffix("MyLibrary.swiftinterface")) let fileContents = try XCTUnwrap(location.uri.fileURL.flatMap({ try String(contentsOf: $0, encoding: .utf8) })) XCTAssertTrue( fileContents.contains( @@ -152,7 +152,7 @@ final class SwiftInterfaceTests: XCTestCase { uri: uri, position: positions["1️⃣"], testClient: testClient, - swiftInterfaceFile: "/Swift.Collection.Array.swiftinterface", + swiftInterfaceFile: "Swift.Collection.Array.swiftinterface", linePrefix: "@inlinable public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]" ) } @@ -171,7 +171,7 @@ final class SwiftInterfaceTests: XCTestCase { uri: project.fileURI, position: project.positions["1️⃣"], testClient: project.testClient, - swiftInterfaceFile: "/Swift.Collection.Array.swiftinterface", + swiftInterfaceFile: "Swift.Collection.Array.swiftinterface", linePrefix: "@inlinable public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]" ) } @@ -192,8 +192,9 @@ private func assertSystemSwiftInterface( ) ) let location = try XCTUnwrap(definition?.locations?.only) - XCTAssertTrue( - location.uri.pseudoPath.hasSuffix(swiftInterfaceFile), + XCTAssertEqual( + location.uri.fileURL?.lastPathComponent, + swiftInterfaceFile, "Path was: '\(location.uri.pseudoPath)'", line: line )