diff --git a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift index c6a70d05..d9927963 100644 --- a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift +++ b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift @@ -448,7 +448,23 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem { throw NonFileURIError(uri: file) } - return try buildTarget.compileArguments(for: fileURL) + let compileArguments = try buildTarget.compileArguments(for: fileURL) + + #if compiler(>=6.1) + #warning("When we drop support for Swift 5.10 we no longer need to adjust compiler arguments for the Modules move") + #endif + // Fix up compiler arguments that point to a `/Modules` subdirectory if the Swift version in the toolchain is less + // than 6.0 because it places the modules one level higher up. + let toolchainVersion = await orLog("Getting Swift version") { try await toolchain.swiftVersion } + guard let toolchainVersion, toolchainVersion < SwiftVersion(6, 0) else { + return compileArguments + } + return compileArguments.map { argument in + if argument.hasSuffix("/Modules"), argument.contains(self.swiftPMWorkspace.location.scratchDirectory.pathString) { + return String(argument.dropLast(8)) + } + return argument + } } package func buildTargets(request: WorkspaceBuildTargetsRequest) async throws -> WorkspaceBuildTargetsResponse { diff --git a/Sources/SKLogging/Logging.swift b/Sources/SKLogging/Logging.swift index 98a94c64..534858f4 100644 --- a/Sources/SKLogging/Logging.swift +++ b/Sources/SKLogging/Logging.swift @@ -19,9 +19,15 @@ package typealias LogLevel = os.OSLogType package typealias Logger = os.Logger package typealias Signposter = OSSignposter +#if compiler(<5.11) +extension OSSignposter: @unchecked Sendable {} +extension OSSignpostID: @unchecked Sendable {} +extension OSSignpostIntervalState: @unchecked Sendable {} +#else extension OSSignposter: @retroactive @unchecked Sendable {} extension OSSignpostID: @retroactive @unchecked Sendable {} extension OSSignpostIntervalState: @retroactive @unchecked Sendable {} +#endif extension os.Logger { package func makeSignposter() -> Signposter { diff --git a/Sources/SKTestSupport/SkipUnless.swift b/Sources/SKTestSupport/SkipUnless.swift index eec72d45..39d22d59 100644 --- a/Sources/SKTestSupport/SkipUnless.swift +++ b/Sources/SKTestSupport/SkipUnless.swift @@ -106,6 +106,304 @@ package actor SkipUnless { } } + package static func sourcekitdHasSemanticTokensRequest( + file: StaticString = #filePath, + line: UInt = #line + ) async throws { + try await shared.skipUnlessSupportedByToolchain(swiftVersion: SwiftVersion(5, 11), file: file, line: line) { + let testClient = try await TestSourceKitLSPClient() + let uri = DocumentURI(for: .swift) + testClient.openDocument("0.bitPattern", uri: uri) + let response = try unwrap( + await testClient.send(DocumentSemanticTokensRequest(textDocument: TextDocumentIdentifier(uri))) + ) + + let tokens = SyntaxHighlightingTokens(lspEncodedTokens: response.data) + + // If we don't have semantic token support in sourcekitd, the second token is an identifier based on the syntax + // tree, not a property. + return tokens.tokens != [ + SyntaxHighlightingToken( + range: Position(line: 0, utf16index: 0).. Int { 1 } + func foo() -> String { "" } + func test() { + _ = 3️⃣foo() + } + """, + uri: uri + ) + + let response = try await testClient.send( + DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["3️⃣"]) + ) + guard case .locations(let locations) = response else { + throw ExpectedLocationsResponse() + } + return locations.count > 0 + } + } } // MARK: - Parsing Swift compiler version diff --git a/Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift b/Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift index c53a4471..341f1a1a 100644 --- a/Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift +++ b/Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift @@ -554,6 +554,12 @@ private func adjustClangCompilerArgumentsForIndexStoreUpdate( return result } +#if compiler(>=6.1) +#warning( + "Remove -fmodules-validate-system-headers from supplementalClangIndexingArgs once all supported Swift compilers have https://github.com/apple/swift/pull/74063" +) +#endif + fileprivate let supplementalClangIndexingArgs: [String] = [ // Retain extra information for indexing "-fretain-comments-from-system-headers", @@ -568,6 +574,11 @@ fileprivate let supplementalClangIndexingArgs: [String] = [ "-Xclang", "-fallow-pcm-with-compiler-errors", "-Wno-non-modular-include-in-framework-module", "-Wno-incomplete-umbrella", + + // sourcekitd adds `-fno-modules-validate-system-headers` before https://github.com/apple/swift/pull/74063. + // This completely disables system module validation and never re-builds pcm for system modules. The intended behavior + // is to only re-build those PCMs once per sourcekitd session. + "-fmodules-validate-system-headers", ] fileprivate extension Sequence { diff --git a/Sources/SourceKitLSP/Swift/CursorInfo.swift b/Sources/SourceKitLSP/Swift/CursorInfo.swift index 863cec65..44ba2ffd 100644 --- a/Sources/SourceKitLSP/Swift/CursorInfo.swift +++ b/Sources/SourceKitLSP/Swift/CursorInfo.swift @@ -29,7 +29,7 @@ struct CursorInfo { /// The annotated declaration XML string. var annotatedDeclaration: String? - #if compiler(>=6.2) + #if swift(>=6.2) #warning( "Documentation transitioned from XML to the raw string in Swift 6.0. We should be able to remove documentationXML now" ) diff --git a/Sources/sourcekit-lsp/SourceKitLSP.swift b/Sources/sourcekit-lsp/SourceKitLSP.swift index 7d5e2049..fac063e3 100644 --- a/Sources/sourcekit-lsp/SourceKitLSP.swift +++ b/Sources/sourcekit-lsp/SourceKitLSP.swift @@ -52,7 +52,11 @@ extension AbsolutePath { .directory } } +#if compiler(<5.11) +extension AbsolutePath: ExpressibleByArgument {} +#else extension AbsolutePath: @retroactive ExpressibleByArgument {} +#endif extension RelativePath { public init?(argument: String) { @@ -65,7 +69,11 @@ extension RelativePath { self = path } } +#if compiler(<5.11) +extension RelativePath: ExpressibleByArgument {} +#else extension RelativePath: @retroactive ExpressibleByArgument {} +#endif extension PathPrefixMapping { public init?(argument: String) { diff --git a/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift b/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift index d7e631cb..c706a8a4 100644 --- a/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift +++ b/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift @@ -89,6 +89,7 @@ final class SwiftPMBuildSystemTests: XCTestCase { } func testBasicSwiftArgs() async throws { + try await SkipUnless.swiftpmStoresModulesInSubdirectory() try await withTestScratchDir { tempDir in try localFileSystem.createFiles( root: tempDir, diff --git a/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift b/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift index c1263ed8..34463f41 100644 --- a/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift +++ b/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift @@ -904,6 +904,7 @@ final class BackgroundIndexingTests: XCTestCase { } func testImportPreparedModuleWithFunctionBodiesSkipped() async throws { + try await SkipUnless.sourcekitdSupportsRename() // This test case was crashing the indexing compiler invocation for Client if Lib was built for index preparation // (using `-enable-library-evolution -experimental-skip-all-function-bodies -experimental-lazy-typecheck`) but the // Client was not indexed with `-experimental-allow-module-with-compiler-errors`. rdar://129071600 @@ -1011,6 +1012,7 @@ final class BackgroundIndexingTests: XCTestCase { } func testLibraryUsedByExecutableTargetAndPackagePlugin() async throws { + try await SkipUnless.swiftPMStoresModulesForTargetAndHostInSeparateFolders() let project = try await SwiftPMTestProject( files: [ "Lib/MyFile.swift": """ @@ -1058,6 +1060,7 @@ final class BackgroundIndexingTests: XCTestCase { } func testCrossModuleFunctionalityEvenIfLowLevelModuleHasErrors() async throws { + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() var options = SourceKitLSPOptions.testDefault() options.backgroundPreparationMode = SourceKitLSPOptions.BackgroundPreparationMode.enabled.rawValue let project = try await SwiftPMTestProject( @@ -1104,6 +1107,7 @@ final class BackgroundIndexingTests: XCTestCase { } func testCrossModuleFunctionalityWithPreparationNoSkipping() async throws { + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() var options = SourceKitLSPOptions.testDefault() options.backgroundPreparationMode = SourceKitLSPOptions.BackgroundPreparationMode.noLazy.rawValue let project = try await SwiftPMTestProject( @@ -1384,6 +1388,7 @@ final class BackgroundIndexingTests: XCTestCase { } func testCancelIndexing() async throws { + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() try SkipUnless.longTestsEnabled() var options = SourceKitLSPOptions.testDefault() diff --git a/Tests/SourceKitLSPTests/CallHierarchyTests.swift b/Tests/SourceKitLSPTests/CallHierarchyTests.swift index 1e8590ea..54f62202 100644 --- a/Tests/SourceKitLSPTests/CallHierarchyTests.swift +++ b/Tests/SourceKitLSPTests/CallHierarchyTests.swift @@ -227,6 +227,7 @@ final class CallHierarchyTests: XCTestCase { } func testIncomingCallHierarchyShowsSurroundingFunctionCall() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() // We used to show `myVar` as the caller here let project = try await IndexedSingleSwiftFileTestProject( """ @@ -268,6 +269,7 @@ final class CallHierarchyTests: XCTestCase { } func testIncomingCallHierarchyFromComputedProperty() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() {} @@ -597,6 +599,7 @@ final class CallHierarchyTests: XCTestCase { } func testUnappliedFunctionReferenceInIncomingCallHierarchy() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() {} @@ -637,6 +640,7 @@ final class CallHierarchyTests: XCTestCase { } func testUnappliedFunctionReferenceInOutgoingCallHierarchy() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() {} @@ -677,6 +681,7 @@ final class CallHierarchyTests: XCTestCase { } func testIncomingCallHierarchyForPropertyInitializedWithClosure() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() -> Int {} @@ -717,6 +722,7 @@ final class CallHierarchyTests: XCTestCase { } func testOutgoingCallHierarchyForPropertyInitializedWithClosure() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() -> Int {} @@ -757,6 +763,7 @@ final class CallHierarchyTests: XCTestCase { } func testInitializerInCallHierarchy() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() {} @@ -799,6 +806,7 @@ final class CallHierarchyTests: XCTestCase { } func testCallHierarchyOfNestedClass() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ func 1️⃣foo() {} @@ -843,6 +851,7 @@ final class CallHierarchyTests: XCTestCase { } func testIncomingCallHierarchyFromComputedMember() async throws { + try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls() let project = try await IndexedSingleSwiftFileTestProject( """ struct Foo { diff --git a/Tests/SourceKitLSPTests/CrossLanguageRenameTests.swift b/Tests/SourceKitLSPTests/CrossLanguageRenameTests.swift index 2a078bfc..ef6279ec 100644 --- a/Tests/SourceKitLSPTests/CrossLanguageRenameTests.swift +++ b/Tests/SourceKitLSPTests/CrossLanguageRenameTests.swift @@ -35,6 +35,7 @@ private let libAlibBCxxInteropPackageManifest = """ final class CrossLanguageRenameTests: XCTestCase { func testZeroArgCFunction() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -76,6 +77,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testMultiArgCFunction() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -117,6 +119,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testCFunctionWithSwiftNameAnnotation() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -159,6 +162,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testZeroArgObjCSelector() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -213,6 +217,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testZeroArgObjCClassSelector() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -267,6 +272,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testOneArgObjCSelector() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -321,6 +327,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testMultiArgObjCSelector() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -375,6 +382,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testObjCSelectorWithSwiftNameAnnotation() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -429,6 +437,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testObjCClass() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -473,6 +482,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testObjCClassWithSwiftNameAnnotation() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -518,6 +528,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testCppMethod() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -571,6 +582,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testCppMethodWithSwiftName() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -624,6 +636,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testCppMethodInObjCpp() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -678,6 +691,7 @@ final class CrossLanguageRenameTests: XCTestCase { func testZeroArgObjCClassSelectorInObjCpp() async throws { try SkipUnless.platformIsDarwin("Non-Darwin platforms don't support Objective-C") + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -731,6 +745,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testRenameCxxClassExposedToSwift() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -762,6 +777,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testRenameCxxMethodExposedToSwift() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ @@ -813,6 +829,7 @@ final class CrossLanguageRenameTests: XCTestCase { } func testRenameSwiftMethodExposedToSwift() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "LibA/include/LibA.h": """ diff --git a/Tests/SourceKitLSPTests/DefinitionTests.swift b/Tests/SourceKitLSPTests/DefinitionTests.swift index 1bace17f..7ca981fc 100644 --- a/Tests/SourceKitLSPTests/DefinitionTests.swift +++ b/Tests/SourceKitLSPTests/DefinitionTests.swift @@ -200,6 +200,7 @@ class DefinitionTests: XCTestCase { } func testAmbiguousDefinition() async throws { + try await SkipUnless.solverBasedCursorInfoWorksForMemoryOnlyFiles() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -567,6 +568,8 @@ class DefinitionTests: XCTestCase { } func testJumpToSatisfiedProtocolRequirementInExtension() async throws { + try await SkipUnless.sourcekitdReportsOverridableFunctionDefinitionsAsDynamic() + let project = try await IndexedSingleSwiftFileTestProject( """ protocol TestProtocol { diff --git a/Tests/SourceKitLSPTests/DependencyTrackingTests.swift b/Tests/SourceKitLSPTests/DependencyTrackingTests.swift index 965f063b..959661d1 100644 --- a/Tests/SourceKitLSPTests/DependencyTrackingTests.swift +++ b/Tests/SourceKitLSPTests/DependencyTrackingTests.swift @@ -46,8 +46,12 @@ final class DependencyTrackingTests: XCTestCase { // Semantic analysis: expect module import error. XCTAssertEqual(initialDiags.diagnostics.count, 1) if let diagnostic = initialDiags.diagnostics.first { + #if compiler(>=6.1) + #warning("When we drop support for Swift 5.10 we no longer need to check for the Objective-C error message") + #endif XCTAssert( - diagnostic.message.contains("No such module"), + diagnostic.message.contains("Could not build Objective-C module") + || diagnostic.message.contains("No such module"), "expected module import error but found \"\(diagnostic.message)\"" ) } diff --git a/Tests/SourceKitLSPTests/ExpandMacroTests.swift b/Tests/SourceKitLSPTests/ExpandMacroTests.swift index 81f425e7..d379a73f 100644 --- a/Tests/SourceKitLSPTests/ExpandMacroTests.swift +++ b/Tests/SourceKitLSPTests/ExpandMacroTests.swift @@ -20,6 +20,7 @@ import XCTest final class ExpandMacroTests: XCTestCase { func testFreestandingMacroExpansion() async throws { try await SkipUnless.canBuildMacroUsingSwiftSyntaxFromSourceKitLSPBuild() + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() let files: [RelativeFileLocation: String] = [ "MyMacros/MyMacros.swift": #""" @@ -174,6 +175,7 @@ final class ExpandMacroTests: XCTestCase { func testAttachedMacroExpansion() async throws { try await SkipUnless.canBuildMacroUsingSwiftSyntaxFromSourceKitLSPBuild() + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() let files: [RelativeFileLocation: String] = [ "MyMacros/MyMacros.swift": #""" @@ -363,6 +365,7 @@ final class ExpandMacroTests: XCTestCase { func testNestedMacroExpansion() async throws { try await SkipUnless.canBuildMacroUsingSwiftSyntaxFromSourceKitLSPBuild() + try await SkipUnless.swiftPMSupportsExperimentalPrepareForIndexing() let files: [RelativeFileLocation: String] = [ "MyMacros/MyMacros.swift": #""" diff --git a/Tests/SourceKitLSPTests/FormattingTests.swift b/Tests/SourceKitLSPTests/FormattingTests.swift index 01550073..0f5f0a53 100644 --- a/Tests/SourceKitLSPTests/FormattingTests.swift +++ b/Tests/SourceKitLSPTests/FormattingTests.swift @@ -18,6 +18,7 @@ import XCTest final class FormattingTests: XCTestCase { func testFormatting() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) @@ -51,6 +52,7 @@ final class FormattingTests: XCTestCase { } func testFormattingNoEdits() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) @@ -76,6 +78,7 @@ final class FormattingTests: XCTestCase { } func testConfigFileOnDisk() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() // We pick up an invalid swift-format configuration file and thus don't set the user-provided options. let project = try await MultiFileTestProject(files: [ ".swift-format": """ @@ -110,6 +113,7 @@ final class FormattingTests: XCTestCase { } func testConfigFileInParentDirectory() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() // We pick up an invalid swift-format configuration file and thus don't set the user-provided options. let project = try await MultiFileTestProject(files: [ ".swift-format": """ @@ -144,6 +148,7 @@ final class FormattingTests: XCTestCase { } func testConfigFileInNestedDirectory() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() // We pick up an invalid swift-format configuration file and thus don't set the user-provided options. let project = try await MultiFileTestProject(files: [ ".swift-format": """ @@ -186,6 +191,7 @@ final class FormattingTests: XCTestCase { } func testInvalidConfigurationFile() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() // We pick up an invalid swift-format configuration file and thus don't set the user-provided options. // The swift-format default is 2 spaces. let project = try await MultiFileTestProject(files: [ @@ -210,6 +216,7 @@ final class FormattingTests: XCTestCase { } func testInsertAndRemove() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) @@ -241,6 +248,7 @@ final class FormattingTests: XCTestCase { } func testMultiLineStringInsertion() async throws { + try await SkipUnless.toolchainContainsSwiftFormat() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) diff --git a/Tests/SourceKitLSPTests/HoverTests.swift b/Tests/SourceKitLSPTests/HoverTests.swift index 813ccd2e..0936b436 100644 --- a/Tests/SourceKitLSPTests/HoverTests.swift +++ b/Tests/SourceKitLSPTests/HoverTests.swift @@ -16,6 +16,7 @@ import XCTest final class HoverTests: XCTestCase { func testBasic() async throws { + try await SkipUnless.sourcekitdReturnsRawDocumentationResponse() try await assertHover( """ /// This is a doc comment for S. @@ -85,6 +86,7 @@ final class HoverTests: XCTestCase { } func testMultiCursorInfoResultsHoverWithDocumentation() async throws { + try await SkipUnless.sourcekitdReturnsRawDocumentationResponse() try await assertHover( """ /// A struct @@ -116,6 +118,7 @@ final class HoverTests: XCTestCase { } func testHoverNameEscapingOnFunction() async throws { + try await SkipUnless.sourcekitdReturnsRawDocumentationResponse() try await assertHover( """ /// this is **bold** documentation @@ -132,6 +135,7 @@ final class HoverTests: XCTestCase { } func testHoverNameEscapingOnOperator() async throws { + try await SkipUnless.sourcekitdReturnsRawDocumentationResponse() try await assertHover( """ /// this is *italic* documentation @@ -148,6 +152,7 @@ final class HoverTests: XCTestCase { } func testPrecondition() async throws { + try await SkipUnless.sourcekitdReturnsRawDocumentationResponse() try await assertHover( """ /// Eat an apple diff --git a/Tests/SourceKitLSPTests/PublishDiagnosticsTests.swift b/Tests/SourceKitLSPTests/PublishDiagnosticsTests.swift index 71a23aee..aac314f3 100644 --- a/Tests/SourceKitLSPTests/PublishDiagnosticsTests.swift +++ b/Tests/SourceKitLSPTests/PublishDiagnosticsTests.swift @@ -182,7 +182,12 @@ final class PublishDiagnosticsTests: XCTestCase { _ = try project.openDocument("LibB.swift") let diagnosticsBeforeBuilding = try await project.testClient.nextDiagnosticsNotification() XCTAssert( - diagnosticsBeforeBuilding.diagnostics.contains { $0.message == "No such module 'LibA'" } + diagnosticsBeforeBuilding.diagnostics.contains(where: { + #if compiler(>=6.1) + #warning("When we drop support for Swift 5.10 we no longer need to check for the Objective-C error message") + #endif + return $0.message == "No such module 'LibA'" || $0.message == "Could not build Objective-C module 'LibA'" + }) ) try await SwiftPMTestProject.build(at: project.scratchDirectory) diff --git a/Tests/SourceKitLSPTests/PullDiagnosticsTests.swift b/Tests/SourceKitLSPTests/PullDiagnosticsTests.swift index 0012b514..0dec41ac 100644 --- a/Tests/SourceKitLSPTests/PullDiagnosticsTests.swift +++ b/Tests/SourceKitLSPTests/PullDiagnosticsTests.swift @@ -204,7 +204,13 @@ final class PullDiagnosticsTests: XCTestCase { DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(bUri)) ) XCTAssert( - (beforeBuilding.fullReport?.items ?? []).contains { $0.message == "No such module 'LibA'" } + (beforeBuilding.fullReport?.items ?? []).contains(where: { + #if compiler(>=6.1) + #warning("When we drop support for Swift 5.10 we no longer need to check for the Objective-C error message") + #endif + return $0.message == "No such module 'LibA'" || $0.message == "Could not build Objective-C module 'LibA'" + } + ) ) let diagnosticsRefreshRequestReceived = self.expectation(description: "DiagnosticsRefreshRequest received") diff --git a/Tests/SourceKitLSPTests/RenameAssertions.swift b/Tests/SourceKitLSPTests/RenameAssertions.swift index 5d2ff6ff..209f0f02 100644 --- a/Tests/SourceKitLSPTests/RenameAssertions.swift +++ b/Tests/SourceKitLSPTests/RenameAssertions.swift @@ -42,6 +42,7 @@ func assertSingleFileRename( file: StaticString = #filePath, line: UInt = #line ) async throws { + try await SkipUnless.sourcekitdSupportsRename() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: language, testName: testName) let positions = testClient.openDocument(markedSource, uri: uri, language: language) @@ -140,6 +141,7 @@ func assertMultiFileRename( file: StaticString = #filePath, line: UInt = #line ) async throws { + try await SkipUnless.sourcekitdSupportsRename() let project = try await SwiftPMTestProject( files: files, manifest: manifest, diff --git a/Tests/SourceKitLSPTests/RenameTests.swift b/Tests/SourceKitLSPTests/RenameTests.swift index bd210209..8f6cead5 100644 --- a/Tests/SourceKitLSPTests/RenameTests.swift +++ b/Tests/SourceKitLSPTests/RenameTests.swift @@ -644,6 +644,7 @@ final class RenameTests: XCTestCase { } func testPrepeareRenameOnDefinition() async throws { + try await SkipUnless.sourcekitdSupportsRename() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -662,6 +663,7 @@ final class RenameTests: XCTestCase { } func testPrepeareRenameOnReference() async throws { + try await SkipUnless.sourcekitdSupportsRename() let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -681,6 +683,7 @@ final class RenameTests: XCTestCase { } func testGlobalRenameC() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "Sources/MyLibrary/include/lib.h": """ @@ -713,6 +716,7 @@ final class RenameTests: XCTestCase { } func testGlobalRenameObjC() async throws { + try await SkipUnless.clangdSupportsIndexBasedRename() try await assertMultiFileRename( files: [ "Sources/MyLibrary/include/lib.h": """ @@ -1086,6 +1090,7 @@ final class RenameTests: XCTestCase { } func testRenameAfterFileMove() async throws { + try await SkipUnless.sourcekitdSupportsRename() let project = try await SwiftPMTestProject( files: [ "definition.swift": """ @@ -1165,6 +1170,7 @@ final class RenameTests: XCTestCase { } func testRenameEnumCaseWithUnlabeledAssociatedValue() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() try await assertSingleFileRename( """ enum MyEnum { @@ -1182,6 +1188,7 @@ final class RenameTests: XCTestCase { } func testAddLabelToEnumCase() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() try await assertSingleFileRename( """ enum MyEnum { @@ -1199,6 +1206,7 @@ final class RenameTests: XCTestCase { } func testRemoveLabelFromEnumCase() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() try await assertSingleFileRename( """ enum MyEnum { @@ -1224,6 +1232,7 @@ final class RenameTests: XCTestCase { } func testRenameEnumCaseWithUnderscoreLabel() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() try await assertSingleFileRename( """ enum MyEnum { @@ -1249,6 +1258,7 @@ final class RenameTests: XCTestCase { } func testRenameEnumCaseWithUnderscoreToLabelMatchingInternalName() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() try await assertSingleFileRename( """ enum MyEnum { @@ -1274,6 +1284,7 @@ final class RenameTests: XCTestCase { } func testRenameEnumCaseWithUnderscoreToLabelNotMatchingInternalName() async throws { + try await SkipUnless.sourcekitdCanRenameEnumCaseLabels() // Note that the renamed code doesn't compile because enum cases can't have an external and internal parameter name. // But it's probably the best thing we can do because we don't want to erase the user-specified internal name, which // they didn't request to rename. Also, this is a pretty niche case and having a special case for it is probably not @@ -1303,6 +1314,7 @@ final class RenameTests: XCTestCase { } func testRenameDoesNotReportEditsIfNoActualChangeIsMade() async throws { + try await SkipUnless.sourcekitdSupportsRename() let project = try await SwiftPMTestProject( files: [ "FileA.swift": """ diff --git a/Tests/SourceKitLSPTests/SemanticTokensTests.swift b/Tests/SourceKitLSPTests/SemanticTokensTests.swift index db13cef4..dd2709dc 100644 --- a/Tests/SourceKitLSPTests/SemanticTokensTests.swift +++ b/Tests/SourceKitLSPTests/SemanticTokensTests.swift @@ -105,6 +105,8 @@ final class SemanticTokensTests: XCTestCase { } func testRanged() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ let x = 1 @@ -124,6 +126,8 @@ final class SemanticTokensTests: XCTestCase { } func testLexicalTokens() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣let 2️⃣x = 3️⃣3 @@ -147,6 +151,8 @@ final class SemanticTokensTests: XCTestCase { } func testLexicalTokensForMultiLineComments() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣let 2️⃣x = 3️⃣3 4️⃣/* @@ -166,6 +172,8 @@ final class SemanticTokensTests: XCTestCase { } func testLexicalTokensForDocComments() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣/** abc */ @@ -179,6 +187,8 @@ final class SemanticTokensTests: XCTestCase { } func testLexicalTokensForBackticks() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣var 2️⃣`if` = 3️⃣20 @@ -223,6 +233,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokens() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣struct 2️⃣X {} @@ -271,6 +283,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokensForProtocols() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣protocol 2️⃣X {} @@ -314,6 +328,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokensForFunctionSignatures() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: "1️⃣func 2️⃣f(3️⃣x: 4️⃣Int, _ 5️⃣y: 6️⃣String) {}", expected: [ @@ -328,6 +344,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokensForFunctionSignaturesWithEmoji() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: "1️⃣func 2️⃣x👍y() {}", expected: [ @@ -338,6 +356,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokensForStaticMethods() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣class 2️⃣X { @@ -382,6 +402,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticTokensForEnumMembers() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣enum 2️⃣Maybe<3️⃣T> { @@ -435,6 +457,8 @@ final class SemanticTokensTests: XCTestCase { } func testRegexSemanticTokens() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣let 2️⃣r = 3️⃣/a[bc]*/ @@ -448,6 +472,8 @@ final class SemanticTokensTests: XCTestCase { } func testOperatorDeclaration() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣infix 2️⃣operator 3️⃣?= :4️⃣ComparisonPrecedence @@ -462,6 +488,8 @@ final class SemanticTokensTests: XCTestCase { } func testEmptyEdit() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -495,6 +523,8 @@ final class SemanticTokensTests: XCTestCase { } func testReplaceUntilMiddleOfToken() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -541,6 +571,8 @@ final class SemanticTokensTests: XCTestCase { } func testReplaceUntilEndOfToken() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -592,6 +624,8 @@ final class SemanticTokensTests: XCTestCase { } func testInsertSpaceBeforeToken() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -627,6 +661,8 @@ final class SemanticTokensTests: XCTestCase { } func testInsertSpaceAfterToken() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -655,6 +691,8 @@ final class SemanticTokensTests: XCTestCase { } func testInsertNewline() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -689,6 +727,8 @@ final class SemanticTokensTests: XCTestCase { } func testRemoveNewline() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -724,6 +764,8 @@ final class SemanticTokensTests: XCTestCase { } func testInsertTokens() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -773,6 +815,8 @@ final class SemanticTokensTests: XCTestCase { } func testSemanticMultiEdit() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + let testClient = try await TestSourceKitLSPClient() let uri = DocumentURI(for: .swift) let positions = testClient.openDocument( @@ -831,6 +875,8 @@ final class SemanticTokensTests: XCTestCase { } func testActor() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣actor 2️⃣MyActor {} @@ -849,6 +895,8 @@ final class SemanticTokensTests: XCTestCase { } func testArgumentLabels() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣func 2️⃣foo(3️⃣arg: 4️⃣Int) {} @@ -867,6 +915,8 @@ final class SemanticTokensTests: XCTestCase { } func testFunctionDeclarationWithFirstAndSecondName() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ 1️⃣func 2️⃣foo(3️⃣arg 4️⃣internalName: 5️⃣Int) {} @@ -882,6 +932,8 @@ final class SemanticTokensTests: XCTestCase { } func testClang() async throws { + try await SkipUnless.sourcekitdHasSemanticTokensRequest() + try await assertSemanticTokens( markedContents: """ int 1️⃣main() {}