Skip to content

Cherry-picks to release/6.0 for sourcekit-lsp update #7520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions BuildSupport/SwiftSyntax/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
include(FetchContent)

set(BUILD_SHARED_LIBS OFF)

if(DEFINED SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE)
file(TO_CMAKE_PATH "${SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE}" swift_syntax_path)
FetchContent_Declare(SwiftSyntax
SOURCE_DIR "${swift_syntax_path}")
else()
FetchContent_Declare(SwiftSyntax
GIT_REPOSITORY https://github.com/apple/swift-syntax
GIT_TAG main)
find_package(SwiftSyntax CONFIG GLOBAL)
if(NOT SwiftSyntax_FOUND)
set(SWIFT_SYNTAX_INSTALL_TARGETS YES)
if(DEFINED SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE)
file(TO_CMAKE_PATH "${SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE}" swift_syntax_path)
FetchContent_Declare(SwiftSyntax
SOURCE_DIR "${swift_syntax_path}")
else()
FetchContent_Declare(SwiftSyntax
GIT_REPOSITORY https://github.com/apple/swift-syntax
GIT_TAG main)
endif()
FetchContent_MakeAvailable(SwiftSyntax)
endif()
FetchContent_MakeAvailable(SwiftSyntax)
26 changes: 6 additions & 20 deletions Sources/PackageModelSyntax/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ target_link_libraries(PackageModelSyntax PUBLIC
PackageLoading
PackageModel

SwiftBasicFormat
SwiftDiagnostics
SwiftIDEUtils
SwiftParser
SwiftSyntax
SwiftSyntaxBuilder
SwiftSyntax::SwiftBasicFormat
SwiftSyntax::SwiftDiagnostics
SwiftSyntax::SwiftIDEUtils
SwiftSyntax::SwiftParser
SwiftSyntax::SwiftSyntax
SwiftSyntax::SwiftSyntaxBuilder
)

# NOTE(compnerd) workaround for CMake not setting up include flags yet
Expand All @@ -41,17 +41,3 @@ install(TARGETS PackageModelSyntax
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
set_property(GLOBAL APPEND PROPERTY SwiftPM_EXPORTS PackageModelSyntax)

set(SWIFT_SYNTAX_MODULES
SwiftBasicFormat
SwiftParser
SwiftParserDiagnostics
SwiftDiagnostics
SwiftSyntax
SwiftSyntaxBuilder
SwiftIDEUtils
)
export(TARGETS ${SWIFT_SYNTAX_MODULES}
NAMESPACE SPMSwiftSyntax::
FILE ${CMAKE_BINARY_DIR}/cmake/modules/SwiftSyntaxConfig.cmake
EXPORT_LINK_INTERFACE_LIBRARIES)
42 changes: 33 additions & 9 deletions Sources/SourceKitLSPAPI/BuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,45 @@ import class Build.BuildPlan
import class Build.ClangTargetBuildDescription
import class Build.SwiftTargetBuildDescription
import struct PackageGraph.ResolvedTarget
import struct PackageGraph.ModulesGraph

public protocol BuildTarget {
var sources: [URL] { get }

/// Whether the target is part of the root package that the user opened or if it's part of a package dependency.
var isPartOfRootPackage: Bool { get }

func compileArguments(for fileURL: URL) throws -> [String]
}
}

private struct WrappedClangTargetBuildDescription: BuildTarget {
private let description: ClangTargetBuildDescription
let isPartOfRootPackage: Bool

init(description: ClangTargetBuildDescription, isPartOfRootPackage: Bool) {
self.description = description
self.isPartOfRootPackage = isPartOfRootPackage
}

extension ClangTargetBuildDescription: BuildTarget {
public var sources: [URL] {
return (try? compilePaths().map { URL(fileURLWithPath: $0.source.pathString) }) ?? []
return (try? description.compilePaths().map { URL(fileURLWithPath: $0.source.pathString) }) ?? []
}

public func compileArguments(for fileURL: URL) throws -> [String] {
let filePath = try resolveSymlinks(try AbsolutePath(validating: fileURL.path))
let commandLine = try self.emitCommandLine(for: filePath)
let commandLine = try description.emitCommandLine(for: filePath)
// First element on the command line is the compiler itself, not an argument.
return Array(commandLine.dropFirst())
}
}

private struct WrappedSwiftTargetBuildDescription: BuildTarget {
private let description: SwiftTargetBuildDescription
let isPartOfRootPackage: Bool

init(description: SwiftTargetBuildDescription) {
init(description: SwiftTargetBuildDescription, isPartOfRootPackage: Bool) {
self.description = description
self.isPartOfRootPackage = isPartOfRootPackage
}

var sources: [URL] {
Expand All @@ -71,17 +85,27 @@ public struct BuildDescription {
}

// FIXME: should not use `ResolvedTarget` in the public interface
public func getBuildTarget(for target: ResolvedTarget) -> BuildTarget? {
public func getBuildTarget(for target: ResolvedTarget, in modulesGraph: ModulesGraph) -> BuildTarget? {
if let description = buildPlan.targetMap[target.id] {
switch description {
case .clang(let description):
return description
return WrappedClangTargetBuildDescription(
description: description,
isPartOfRootPackage: modulesGraph.rootPackages.map(\.id).contains(description.package.id)
)
case .swift(let description):
return WrappedSwiftTargetBuildDescription(description: description)
return WrappedSwiftTargetBuildDescription(
description: description,
isPartOfRootPackage: modulesGraph.rootPackages.map(\.id).contains(description.package.id)
)
}
} else {
if target.type == .plugin, let package = self.buildPlan.graph.package(for: target) {
return PluginTargetBuildDescription(target: target, toolsVersion: package.manifest.toolsVersion)
return PluginTargetBuildDescription(
target: target,
toolsVersion: package.manifest.toolsVersion,
isPartOfRootPackage: modulesGraph.rootPackages.map(\.id).contains(package.id)
)
}
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ private import class PackageModel.UserToolchain
struct PluginTargetBuildDescription: BuildTarget {
private let target: ResolvedTarget
private let toolsVersion: ToolsVersion
let isPartOfRootPackage: Bool

init(target: ResolvedTarget, toolsVersion: ToolsVersion) {
init(target: ResolvedTarget, toolsVersion: ToolsVersion, isPartOfRootPackage: Bool) {
assert(target.type == .plugin)
self.target = target
self.toolsVersion = toolsVersion
self.isPartOfRootPackage = isPartOfRootPackage
}

var sources: [URL] {
Expand Down
9 changes: 5 additions & 4 deletions Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ class SourceKitLSPAPITests: XCTestCase {
)
let description = BuildDescription(buildPlan: plan)

try description.checkArguments(for: "exe", graph: graph, partialArguments: ["-module-name", "exe", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/exe.build/exe.swiftmodule"])
try description.checkArguments(for: "lib", graph: graph, partialArguments: ["-module-name", "lib", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/Modules/lib.swiftmodule"])
try description.checkArguments(for: "exe", graph: graph, partialArguments: ["-module-name", "exe", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/exe.build/exe.swiftmodule"], isPartOfRootPackage: true)
try description.checkArguments(for: "lib", graph: graph, partialArguments: ["-module-name", "lib", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/Modules/lib.swiftmodule"], isPartOfRootPackage: true)
}
}

extension SourceKitLSPAPI.BuildDescription {
@discardableResult func checkArguments(for targetName: String, graph: ModulesGraph, partialArguments: [String]) throws -> Bool {
@discardableResult func checkArguments(for targetName: String, graph: ModulesGraph, partialArguments: [String], isPartOfRootPackage: Bool) throws -> Bool {
let target = try XCTUnwrap(graph.allTargets.first(where: { $0.name == targetName }))
let buildTarget = try XCTUnwrap(self.getBuildTarget(for: target))
let buildTarget = try XCTUnwrap(self.getBuildTarget(for: target, in: graph))

guard let file = buildTarget.sources.first else {
XCTFail("build target \(targetName) contains no files")
Expand All @@ -70,6 +70,7 @@ extension SourceKitLSPAPI.BuildDescription {
let result = arguments.contains(partialArguments)

XCTAssertTrue(result, "could not match \(partialArguments) to actual arguments \(arguments)")
XCTAssertEqual(buildTarget.isPartOfRootPackage, isPartOfRootPackage)
return result
}
}