mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-06-24 12:21:58 +02:00
b9e4c67793
Delete `Collection+Only.swift`, `Duration+Seconds.swift`, `FileManagerExtensions.swift`, `PipeAsStringHandler.swift`, and `URLExtensions.swift` from `Sources/SwiftExtensions/`. The same APIs now live in swift-tools-protocols as `@_spi(SourceKitLSP) public` declarations. Update each call site to add `@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions` next to the existing `import SwiftExtensions`. Add the `_ToolsProtocolsSwiftExtensionsForPlugin` dependency and the `ToolsProtocolsSwiftExtensions=_ToolsProtocolsSwiftExtensionsForPlugin` module alias to the `SwiftSourceKitClientPlugin` target in both `Package.swift` and the corresponding `CMakeLists.txt`.
338 lines
11 KiB
Swift
338 lines
11 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import BuildServerIntegration
|
|
@_spi(SourceKitLSP) import BuildServerProtocol
|
|
@_spi(SourceKitLSP) import LanguageServerProtocol
|
|
@_spi(Testing) @_spi(SourceKitLSP) import SKLogging
|
|
import SKTestSupport
|
|
import SwiftExtensions
|
|
@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions
|
|
import XCTest
|
|
|
|
class CopyDestinationTests: SourceKitLSPTestCase {
|
|
actor BuildServer: CustomBuildServer {
|
|
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
|
|
private let projectRoot: URL
|
|
|
|
var headerCopyDestination: URL {
|
|
projectRoot.appending(components: "header-copy", "CopiedTest.h")
|
|
}
|
|
|
|
init(projectRoot: URL, connectionToSourceKitLSP: any Connection) {
|
|
self.projectRoot = projectRoot
|
|
}
|
|
|
|
func initializeBuildRequest(_ request: InitializeBuildRequest) async throws -> InitializeBuildResponse {
|
|
return try initializationResponseSupportingBackgroundIndexing(
|
|
projectRoot: projectRoot,
|
|
outputPathsProvider: false
|
|
)
|
|
}
|
|
|
|
func buildTargetSourcesRequest(_ request: BuildTargetSourcesRequest) -> BuildTargetSourcesResponse {
|
|
return BuildTargetSourcesResponse(items: [
|
|
SourcesItem(
|
|
target: .dummy,
|
|
sources: [
|
|
SourceItem(
|
|
uri: DocumentURI(projectRoot.appending(component: "Test.c")),
|
|
kind: .file,
|
|
generated: false,
|
|
dataKind: .sourceKit,
|
|
data: SourceKitSourceItemData(
|
|
language: .c,
|
|
kind: .source,
|
|
).encodeToLSPAny()
|
|
),
|
|
SourceItem(
|
|
uri: DocumentURI(projectRoot.appending(component: "Test.h")),
|
|
kind: .file,
|
|
generated: false,
|
|
dataKind: .sourceKit,
|
|
data: SourceKitSourceItemData(
|
|
language: .c,
|
|
kind: .header,
|
|
copyDestinations: [DocumentURI(headerCopyDestination)]
|
|
).encodeToLSPAny()
|
|
),
|
|
]
|
|
)
|
|
])
|
|
}
|
|
|
|
func textDocumentSourceKitOptionsRequest(
|
|
_ request: TextDocumentSourceKitOptionsRequest
|
|
) throws -> TextDocumentSourceKitOptionsResponse? {
|
|
return TextDocumentSourceKitOptionsResponse(compilerArguments: [
|
|
request.textDocument.uri.pseudoPath,
|
|
"-I", try headerCopyDestination.deletingLastPathComponent().filePath,
|
|
"-D", "FOO",
|
|
])
|
|
}
|
|
|
|
func prepareTarget(_ request: BuildTargetPrepareRequest) async throws -> BuildTargetPrepareResponse {
|
|
try FileManager.default.createDirectory(
|
|
at: headerCopyDestination.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true
|
|
)
|
|
try FileManager.default.copyItem(
|
|
at: projectRoot.appending(component: "Test.h"),
|
|
to: headerCopyDestination
|
|
)
|
|
return BuildTargetPrepareResponse()
|
|
}
|
|
}
|
|
|
|
func testJumpToCopiedHeader() async throws {
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: [
|
|
"Test.h": """
|
|
void hello();
|
|
""",
|
|
"Test.c": """
|
|
#include <CopiedTest.h>
|
|
|
|
void test() {
|
|
1️⃣hello();
|
|
}
|
|
""",
|
|
],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: true,
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
|
|
let (uri, positions) = try project.openDocument("Test.c")
|
|
let response = try await project.testClient.send(
|
|
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
|
|
)
|
|
XCTAssertEqual(response?.locations?.map(\.uri), [try project.uri(for: "Test.h")])
|
|
}
|
|
|
|
func testFindReferencesInCopiedHeader() async throws {
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: [
|
|
"Test.h": """
|
|
void 1️⃣hello();
|
|
""",
|
|
"Test.c": """
|
|
#include <CopiedTest.h>
|
|
|
|
void test() {
|
|
2️⃣hello();
|
|
}
|
|
""",
|
|
],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: true
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
|
|
let (uri, positions) = try project.openDocument("Test.c")
|
|
let response = try await project.testClient.send(
|
|
ReferencesRequest(
|
|
textDocument: TextDocumentIdentifier(uri),
|
|
position: positions["2️⃣"],
|
|
context: ReferencesContext(includeDeclaration: true)
|
|
)
|
|
)
|
|
let expected = [
|
|
try project.location(from: "2️⃣", to: "2️⃣", in: "Test.c"),
|
|
try project.location(from: "1️⃣", to: "1️⃣", in: "Test.h"),
|
|
]
|
|
XCTAssertEqual(response, expected)
|
|
}
|
|
|
|
func testFindDeclarationInCopiedHeader() async throws {
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: [
|
|
"Test.h": """
|
|
void 1️⃣hello2️⃣();
|
|
""",
|
|
"Test.c": """
|
|
#include <CopiedTest.h>
|
|
|
|
void hello() {}
|
|
|
|
void test() {
|
|
3️⃣hello();
|
|
}
|
|
""",
|
|
],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: true
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
|
|
let (uri, positions) = try project.openDocument("Test.c")
|
|
let response = try await project.testClient.send(
|
|
DeclarationRequest(
|
|
textDocument: TextDocumentIdentifier(uri),
|
|
position: positions["3️⃣"]
|
|
)
|
|
)
|
|
XCTAssertEqual(
|
|
response?.locations,
|
|
[
|
|
try project.location(from: "1️⃣", to: "2️⃣", in: "Test.h")
|
|
]
|
|
)
|
|
}
|
|
|
|
func testWorkspaceSymbolsInCopiedHeader() async throws {
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: [
|
|
"Test.h": """
|
|
void 1️⃣hello();
|
|
""",
|
|
"Test.c": """
|
|
#include <CopiedTest.h>
|
|
|
|
void test() {
|
|
hello();
|
|
}
|
|
""",
|
|
],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: true
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
|
|
_ = try project.openDocument("Test.c")
|
|
let response = try await project.testClient.send(
|
|
WorkspaceSymbolsRequest(query: "hello")
|
|
)
|
|
let item = try XCTUnwrap(response?.only)
|
|
guard case .symbolInformation(let info) = item else {
|
|
XCTFail("Expected a symbol information")
|
|
return
|
|
}
|
|
XCTAssertEqual(info.location, try project.location(from: "1️⃣", to: "1️⃣", in: "Test.h"))
|
|
}
|
|
|
|
func testJumpToCopiedHeaderJumpsToCopyIfOriginalDoesNotExist() async throws {
|
|
actor BuildServer: CustomBuildServer {
|
|
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
|
|
private let projectRoot: URL
|
|
|
|
var headerCopyDestination: URL {
|
|
projectRoot.appending(components: "header-copy", "CopiedTest.h")
|
|
}
|
|
|
|
init(projectRoot: URL, connectionToSourceKitLSP: any Connection) {
|
|
self.projectRoot = projectRoot
|
|
}
|
|
|
|
func initializeBuildRequest(_ request: InitializeBuildRequest) async throws -> InitializeBuildResponse {
|
|
return try initializationResponseSupportingBackgroundIndexing(
|
|
projectRoot: projectRoot,
|
|
outputPathsProvider: false
|
|
)
|
|
}
|
|
|
|
func buildTargetSourcesRequest(_ request: BuildTargetSourcesRequest) -> BuildTargetSourcesResponse {
|
|
return BuildTargetSourcesResponse(items: [
|
|
SourcesItem(
|
|
target: .dummy,
|
|
sources: [
|
|
SourceItem(
|
|
uri: DocumentURI(projectRoot.appending(component: "Test.c")),
|
|
kind: .file,
|
|
generated: false,
|
|
dataKind: .sourceKit,
|
|
data: SourceKitSourceItemData(language: .c).encodeToLSPAny()
|
|
),
|
|
SourceItem(
|
|
uri: DocumentURI(projectRoot.appending(component: "Test.h")),
|
|
kind: .file,
|
|
generated: false,
|
|
dataKind: .sourceKit,
|
|
data: SourceKitSourceItemData(
|
|
language: .c,
|
|
kind: .header,
|
|
copyDestinations: [DocumentURI(headerCopyDestination)]
|
|
).encodeToLSPAny()
|
|
),
|
|
]
|
|
)
|
|
])
|
|
}
|
|
|
|
func textDocumentSourceKitOptionsRequest(
|
|
_ request: TextDocumentSourceKitOptionsRequest
|
|
) throws -> TextDocumentSourceKitOptionsResponse? {
|
|
return TextDocumentSourceKitOptionsResponse(compilerArguments: [
|
|
request.textDocument.uri.pseudoPath, "-I", try headerCopyDestination.deletingLastPathComponent().filePath,
|
|
])
|
|
}
|
|
|
|
func prepareTarget(_ request: BuildTargetPrepareRequest) async throws -> BuildTargetPrepareResponse {
|
|
try FileManager.default.createDirectory(
|
|
at: headerCopyDestination.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true
|
|
)
|
|
try await """
|
|
void hello();
|
|
""".writeWithRetry(to: headerCopyDestination)
|
|
return BuildTargetPrepareResponse()
|
|
}
|
|
}
|
|
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: [
|
|
"Test.c": """
|
|
#include <CopiedTest.h>
|
|
|
|
void test() {
|
|
1️⃣hello();
|
|
}
|
|
"""
|
|
],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: true,
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
|
|
let (uri, positions) = try project.openDocument("Test.c")
|
|
let response = try await project.testClient.send(
|
|
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
|
|
)
|
|
assertEqual(response?.locations?.map(\.uri), [try await DocumentURI(project.buildServer().headerCopyDestination)])
|
|
}
|
|
|
|
func testSemanticFunctionalityInCopiedHeader() async throws {
|
|
let contents = """
|
|
#ifdef FOO
|
|
typedef void 1️⃣MY_VOID2️⃣;
|
|
#else
|
|
typedef void MY_VOID;
|
|
#endif
|
|
3️⃣MY_VOID hello();
|
|
"""
|
|
|
|
let project = try await CustomBuildServerTestProject(
|
|
files: ["Test.h": contents],
|
|
buildServer: BuildServer.self,
|
|
enableBackgroundIndexing: false,
|
|
)
|
|
try await project.testClient.send(SynchronizeRequest(copyFileMap: true))
|
|
let headerUri = try await DocumentURI(project.buildServer().headerCopyDestination)
|
|
|
|
let positions = project.testClient.openDocument(contents, uri: headerUri, language: .c)
|
|
let response = try await project.testClient.send(
|
|
DefinitionRequest(textDocument: TextDocumentIdentifier(headerUri), position: positions["3️⃣"])
|
|
)
|
|
XCTAssertEqual(response?.locations, [try project.location(from: "1️⃣", to: "2️⃣", in: "Test.h")])
|
|
}
|
|
}
|