ThreadSafeBox is a `class` wrapping a `Mutex<Value>`. When stored as
a property of another class or actor, the outer reference type already
provides identity, so the extra ThreadSafeBox class indirection is just a
redundant heap allocation. Replace `ThreadSafeBox<T>` with `Mutex<T>` at
those sites.
Function-local ThreadSafeBox uses are unchanged since they need class
identity to be capturable in `@Sendable` closures.
CustomBuildServerTestProject.buildServerBox is also unchanged: it is
value-captured into a closure stored before `super.init`, which a
~Copyable Mutex can't support without a class wrapper.
Port SourceKitD's fileprivate `computeIfNil` extension from ThreadSafeBox
to Mutex (now `borrowing`).
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`.
Delete sourcekit-lsp's `Sources/SwiftExtensions/ThreadSafeBox.swift`
and the now-unused `NSLock+WithLock.swift`.
Use the `Mutex`-backed `ThreadSafeBox` from swift-tools-protocols'
Adjust call sites for the new API: e.g.
`foo.value.mutate()` with `foo.withLock { $0.mutate() }` because it
doesn't provide `_modify` accessor.
Introduce `SourceKitDCore` as the protocol boundary between dylib
lifecycle management and the high-level `SourceKitD` API. Its single
lifecycle entry point, `initializeService(api:notificationCallback:)`,
receives the already-loaded `sourcekitd_api_functions_t` from
`SourceKitD.init(core:)`.
`SourceKitDCoreImpl` is the standard implementation: `init` opens the
dylib; `initializeService` registers any plugin paths, calls
`api.initialize()`, and wires the notification handler; `deinit` calls
`shutdown()` and closes the handle. Pre-initialized conformances
implement `initializeService` as a no-op.
Wire a `sourcekitdCoreInjector` hook through `Hooks` so an embedding
host can return a pre-initialized `SourceKitDCore` for a given toolchain
path, preventing `sourcekitd_initialize()` from being called a second
time.
Declare `SourceKitDCoreForPlugin` at its use sites so each call site
can express the exact deinit behavior it needs: `dlclose` for handles
acquired via `RTLD_NOLOAD`, and `leak` for externally-owned handles.
Replace usages of `Optional.map` and `Optional.flatMap` by if expressions or other expressions.
I personally find `Optional.map` to be hard to read because `map` implies mapping a collection to me. Usually the alternative constructs seem clearer to me.
When `DYLD_(FRAMEWORK|LIBRARY)_PATH` is set, `dlopen` will first check
if the basename of the provided path is within any of its search paths.
Thus it's possible that only a single library is loaded for each
toolchain, rather than a separate like we expect. The paths should be
equal in this case, since the client plugin is loaded based on the path
of `sourcekitd.framework` (and we should only have one for the same
reason). Allow this case and just avoid re-initializing.
Depends on https://github.com/swiftlang/swift/pull/83378
---
Adds support for the LSP signature help request.
> [!NOTE]
> As of https://github.com/swiftlang/swift/pull/83378, SourceKitD still
doesn't separate parameter documentation from the signature
documentation and thus parameters don't have their own separate
documentation. This should just work once SourceKitD implements this
functionality and we'll only need to modify the tests.
When resolving documentation for code completion items, we fetch full
documentation through the newly added
`swiftide_completion_item_get_doc_full_copy` SourceKitD function, if not
found we fallback to brief documentation as before using
`swiftide_completion_item_get_doc_brief`.
> [!NOTE]
> Unlike brief documentation, SourceKitD doesn't cache full
documentation for completion results to avoid bloating memory with a lot
of large strings.
>
> As of now, SourceKit-LSP doesn't cache completion item documentation
either, should we introduce a new full documentation cache (e.g. using
`LRUCache`)?
- I think there are valid calls with mixing inline and trailing closures (notably `Debouncer`), so I’m considering whether we should disable that rule.
- The `forEach` rule is a little annoying because we have `forEach` on `SKDResponseArray`. But it caught two cases of using `forEach` on arrays, so I think it’s worth keeping.
This should be a last stop-gap measure in case sourcekitd or clangd get stuck, don’t respond to any requests anymore and don’t honor cancellation either. In that case we can restore SourceKit-LSP behavior by killing them and using the crash recovery logic to restore functionality.
rdar://149492159
Just something I noticed while looking through code. I am not aware of any issues caused by this.
Also relax the `precondition` in `DLHandle.deinit` to a fault. If we do not close a `DLHandle`, that’s a bug but it’s not so bad that we should crash sourcekit-lsp for it.
We don’t have any guarantees which thread these blocks will be called on by sourcekitd, so we shouldn’t make any assumptions about it in Swift. We should thus mark them as Sendable.
There is only one real class that implements the `SourceKitD` protocol, so there really isn’t any need for the protocol + class split at all. Unify them to make code simpler to reason about.
Otherwise, the cancellation could get handled before the request actually gets sent to sourcekitd, which is not what we want to test here. There appears to be a second underlying issue that causes unexpected results when we cancel the fast completion request after sending the slow completion request. I’ll look at that in a follow-up PR.
Otherwise, we would log sending the sourcekitd request even if the task was already cancelled and we thus took an early exit in `withCancellableCheckedThrowingContinuation`.
We need to jump through a few extra hoops when the SourceKit plugin is located in SourceKit-LSP’s build folder and we are using `sourcekitd_plugin_initialize` instead of `sourcekitd_plugin_initialize_2`.
This adds a sourcekitd plugin that drives the code completion requests. It also includes a `CompletionScoring` module that’s used to rank code completion results based on their contextual match, allowing us to show more relevant code completion results at the top.
We made quite a few fixes recently to make sure that path handling works correctly using `URL` on Windows. Use `URL` in most places to have a single type that represents file paths instead of sometimes using `AbsolutePath`.
While doing so, also remove usages of `TSCBasic.FileSystem` an `InMemoryFileSystem`. The pattern of using `InMemoryFileSystem` for tests was never consistently used and it was a little confusing that some types took a `FileSystem` parameter while other always assumed to work on the local file system.
Do one of the following for every `FIXME` or `TODO` comment
- Add an issue that tracks the task
- Remove the comment if we are not planning to address it
Fixes all build warnings in SourceKit-LSP so that it builds without any issues using recent Swift development snapshots (`swift-DEVELOPMENT-SNAPSHOT-2024-07-22-a` and `swift-6.0-DEVELOPMENT-SNAPSHOT-2024-07-24-a`)