Commit Graph

1340 Commits

Author SHA1 Message Date
Rintaro Ishizaki f0231e287f Workspace: explicit weak captures in semanticIndexManager callbacks
Inner closures captured `sourceKitLSPServer` implicitly. The outer
`Task` already captures it weakly, making it a `var` in scope; inner
@Sendable closures that capture this `var` implicitly trigger the
`SendableClosureCaptures` diagnostic on compiler configurations
without `ImmutableWeakCaptures`.

Add explicit `[weak sourceKitLSPServer]` to each inner closure so the
capture binds cleanly to a fresh weak local.
2026-06-02 11:06:52 -07:00
Rintaro Ishizaki 7c99f4f0e7 Use swift-tools-protocols's ThreadSafeBox
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.
2026-05-27 12:01:07 -07:00
Rintaro Ishizaki a39c92022f Add forOpenDocument label to language service lookup methods
Rename languageServices(for:), primaryLanguageService(for:), and their
internal counterparts to use the `forOpenDocument` label, so the
precondition that the document must already be open is visible at call
sites.

Also make primaryLanguageService(forOpenDocument:) throw instead of
returning an optional, and switch several resolve-style handlers from
the find-or-create primaryLanguageService(for:_:) to
primaryLanguageService(forOpenDocument:), since those call sites already
have an open document in hand.
2026-05-20 10:31:44 -07:00
Rintaro Ishizaki f56a27b996 Fix build warnings 2026-05-18 18:04:44 -07:00
Rintaro Ishizaki 626861d316 Merge pull request #2654 from rintaro/per-workspace-language-services
Scope language service lifetime to workspace
2026-05-18 14:59:47 -07:00
Rintaro Ishizaki f84abc1eb2 Use 'weak let' for immutable weak references (SE-0481)
Replace 'weak var' with 'weak let' for weak reference properties that are
set in init and never reassigned, using the Swift 6.3 feature introduced
by SE-0481.
2026-05-18 09:28:10 -07:00
Rintaro Ishizaki f2a121453d Scope language service instances per workspace
Previously, language services were held in a global registry on
SourceKitLSPServer and shared across workspaces, requiring complex
lifetime tracking (isImmortal, shutdownOrphanedLanguageServices) to
decide when to tear them down. In practice, every language service
already stored workspace-specific properties (buildServerManager,
semanticIndexManagerTask), so sharing them across workspaces was never
truly safe. Giving each Workspace its own service instances simplifies
lifetime management: services are created when needed and shut down
with their workspace.

Remove LanguageService.isImmortal, the workspace parameter from
canHandle(toolchain:), and the initialize/clientInitialized protocol
requirements.
2026-05-18 09:21:01 -07:00
Rintaro Ishizaki a559d60451 Merge pull request #2648 from rintaro/language-service-close
Preserve language service when closing generated interface
2026-05-14 16:26:50 -07:00
Rintaro Ishizaki 1d20e3f32e Merge pull request #2647 from rintaro/open-quickly-revise
Move Open Quickly and Jump to Definition docs to Contributor Documentation
2026-05-14 06:41:48 -07:00
Rintaro Ishizaki b60b9582ac Move language-service retention check into Workspace
The buildSettingsFile key is an implementation detail of Workspace's
language-service dictionary, so the guard that prevents removing a
still-needed service belongs there rather than in SourceKitLSPServer.
2026-05-13 20:59:29 -07:00
Edward Lee ca91f5ff4f Preserve language service when closing generated interface documents
Closing a generated interface document (sourcekit-lsp:// URI) was
removing the language service for the originating source file because
both share the same buildSettingsFile key. Guard the removal so it
only happens when no other open document shares that key.

Relates to #2209
2026-05-13 15:56:27 -07:00
Rintaro Ishizaki 292985e7dd Remove redundant fragment-clearing when constructing moduleFileURI 2026-05-13 10:25:09 -07:00
25harsh 90ceac197d Use ExpressibleByLiteral conformances for LSPAny 2026-05-13 16:19:42 +05:30
Rintaro Ishizaki 223a88cb8c Add workspace/symbolNames and workspace/symbolInfo LSP extensions (#2619)
- **`sourcekit/workspace/symbolNames`** — returns a flat, deduplicated
list of every symbol name in the workspace index (source and indexed
system modules). Clients use this to drive their search UI locally.

- **`sourcekit/workspace/symbolInfo`** — given a list of exact symbol
names, returns `WorkspaceSymbolItem` for each occurrence across all
workspaces, for display in the search result list. Source-file symbols
get `SymbolInformation` with a `file://` location. SDK/stdlib symbols
get a `WorkspaceSymbol` with `location: .uri(…)` The client must call
`workspaceSymbol/resolve` after the user selects an SDK/stdlib symbol to
obtain the concrete interface location.

- **`workspaceSymbol/resolve`** — resolves the deferred
`WorkspaceSymbol` location from `sourcekit/workspace/symbolInfo`. Parses
the `?module=` value into `moduleName`/`groupName`, finds a real source
file via `mainFiles(containing:)`, calls `openGeneratedInterface`, and
returns the symbol with `location` replaced by a full
`sourcekit-lsp://generated-swift-interface/` URI + range (or a temp
`file://` path for clients without `workspace/getReferenceDocument`
support).
2026-05-12 22:21:17 -07:00
Rintaro Ishizaki eab4f58f32 Simplify adjusted(for:) implementations in LSP+CopiedFileMap
The range is never changed by URI adjustment, so there's no need to
construct intermediate Location values just to extract the URI.
2026-05-10 17:12:15 -07:00
Rintaro Ishizaki 2d320b288c Fix missing CopiedFileMap adjustments for WorkspaceEdit and TypeHierarchyItem
- WorkspaceEdit.adjusted(for:) was using originalURI(for:) ?? uri, which
  skips the file-existence check; switch to adjustedURI(for:)
- TypeHierarchyItem.adjusted(for:) was not adjusting the URI stored in
  data, unlike CallHierarchyItem
2026-05-10 17:12:12 -07:00
Rintaro Ishizaki 01b793dab4 Merge pull request #2637 from rintaro/lsp-messsage-metadata-structs
Replace manual LSPAny data handling with typed structs
2026-05-10 11:22:35 -07:00
Rintaro Ishizaki 2773bcdfa2 Merge pull request #2633 from rintaro/sourcekitd-inject
Allow injection of a pre-initialized sourcekitd connection
2026-05-07 19:57:41 -07:00
Rintaro Ishizaki 83afc9d1e1 Move CopiedFileMap LSP adjustments to extensions on LSP types
`CopiedFileMap` previously held methods like
`workspaceEditAdjustedForCopiedFiles`,
`callHierarchyItemAdjustedForCopiedFiles`, etc. that encoded knowledge
of high-level LSP message types into `BuildServerIntegration`.

Replace them with `adjusted(for:)` methods on each LSP type
(`Location`, `[Location]`, `LocationsOrLocationLinksResponse`,
`WorkspaceEdit`, `CallHierarchyItem`, `TypeHierarchyItem`) in a new
`LSP+CopiedFileMap.swift` in the SourceKitLSP module. The primitive
URI remapping is extracted into `CopiedFileMap.adjustedURI(for:)`
which remains in `BuildServerIntegration`.

`CallHierarchyItem.adjusted(for:)` also drops manual `LSPAny`
dictionary construction in favour of `HierarchyItemData`.
2026-05-07 16:10:02 -07:00
Rintaro Ishizaki 070bc52b8c Use typed structs for LSP item data fields instead of manual LSPAny 2026-05-07 15:25:18 -07:00
Rintaro Ishizaki 4b2fa3193a Allow injection of a pre-initialized sourcekitd connection
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.
2026-05-07 09:58:47 -07:00
Alex Hoppen 234890c484 Merge pull request #2607 from DeeSee/fix-duplicate-rename-edits
Make RenameLocation unique
2026-05-04 19:23:37 +02:00
Alexander Skvortsov 0b1a2cb372 Make RenameLocation unique 2026-04-30 17:27:19 +03:00
Alex Hoppen caa4b97c57 Merge pull request #2597 from Steffeeen/inlay-hint-performance
Cache inlay hints to avoid flickering
2026-04-30 15:37:42 +02:00
Rintaro Ishizaki 3d7ebf7f20 Factor out CopiedFileMap as a Sendable value type
Extract the copied-file adjustment logic from BuildServerManager into a
Sendable value type CopiedFileMap. Call sites snapshot cachedCopiedFileMap
once per request (hoisted before loops) instead of awaiting the actor on
every iteration.
2026-04-28 12:12:40 -07:00
Rintaro Ishizaki 4fa1b30d52 Add SymbolLocation.lspPosition, lspLocation, and make documentUri optional
Add computed properties to `SymbolLocation` that centralise the
index-to-LSP coordinate conversion:

- `uri: DocumentURI?` — returns nil when `path` is empty.
- `lspPosition: Position` — converts the 1-based line/utf8Column to a
  0-based LSP Position, using UTF-8 column as a UTF-16 approximation.
- `lspLocation: Location?` — wraps `documentUri` + `lspPosition` into
  an LSP Location, returning nil when `path` is empty.

Update all call sites.
2026-04-28 06:56:55 -07:00
Alex Hoppen b4fafb64b3 Fix build warnings
Fix all build warnings except those caused by using old DocC request/response types, which are a little harder to resolve.
2026-04-12 16:11:11 +10:00
Steffeeen a2ea03c53f Add DocoumentSnapshot.absolutePositionRange() 2026-04-07 10:47:59 +02:00
Steffeeen aa3497e96c Rename DocumentSnapshot.absolutePositionRange() to positionRange()
This matches the naming of the `position` and `absolutePosition`
methods.
2026-04-07 10:47:59 +02:00
Alex Hoppen facfb28d39 Don’t implicitly cancel requests when an edit is detected
Instead, use `staleRequestSupport.retryOnContentModified` as an indicator which requests should return a `ContentModified` error when the document is modified. This fixes https://github.com/swiftlang/sourcekit-lsp/issues/2136 by no longer implicitly cancelling inlayHints in Helix while still implicitly cancelling semantic tokens request, which was the motivation for https://github.com/swiftlang/sourcekit-lsp/pull/1629.

Fixes #2136
2026-04-03 13:38:40 +02:00
Kavon Farvardin e45119ea18 Merge pull request #2416 from ahoppen/any-error
Allow `QueueBasedMessageHandler.handle` to return `any Error` instead of `ResponseError`
2026-04-02 08:55:26 -07:00
Rintaro Ishizaki f54f5c9ad0 Fix build errors and warnings in 6.2 toolchain 2026-03-30 14:57:07 -07:00
Rintaro Ishizaki 64aa354caf [TestDiscovery] "/refresh" style tests/playgrounds requests
When the client opts in to `workspace/tests/refresh` or
`workspace/playgrounds/refresh` via experimental client capabilities,
SourceKit-LSP now maintains a proactive cache of the current test and
playground lists and sends the corresponding `workspace/.../refresh`
notification whenever the cache changes. `workspaceTests()` /
`workspacePlaygrounds()` then serve subsequent fetch requests directly
from the cache.

Add `EntryPointManager`: runs background scans, stores the results,
fires callbacks on changes:
 - Start scanning when build targets are updated including initial
   updates, any watched files are changed, and index is updated.
 - Send '/refresh' server initiated requests when the cache has changed.
 - Coalesces rapid invalidations by cancelling any in-flight refresh task.

Also:
- Simplify `SourceKitIndexDelegate` from an `actor` with `AtomicInt32`
  to a plain `class`, since it is only called from IndexStoreDB's
  internal serial dispatch queue.
2026-03-27 09:32:59 -07:00
Paul LeMarquand 9af9441d59 Merge pull request #2575 from plemarquand/dup-test-discovery-fix
When semantic test discovery encounters XCTest methods in an extension it adds the extension definition to the root items list for each child test method. With N test methods, the same extension root appears N times, each copy receiving all N children. After merging, this produces N*N test items instead of N.

The bug is normally masked by the syntactic index, which provides correct results that take priority via combineTests(). This bug was exposed while I was debugging why tests generated by build plugins would appear multiple times. Turns out because they don't exist on disk at the time of the syntatic scan only the semantic results are used, which surfaced the issue.

The fix is to track already-added extension USRs to ensure each extension added once as a root item.
2026-03-25 12:26:14 -04:00
Paul LeMarquand de2500e032 Simplify insertion check by using existing testSymbolUsrs 2026-03-24 10:01:44 -04:00
Alex Hoppen 97ce44d98c Merge pull request #2412 from ahoppen/semantic-functionality-in-copies
Provide semantic functionality in copy destinations
2026-03-24 14:59:09 +01:00
Alex Hoppen 9d7e7f3c30 Provide semantic functionality in copy destinations
If we have a source item `include/Test.h` that gets copied to `build/Test.h`, we currently don’t provide any semantic functionality for `build/Test.h`. Improve the build settings fallback logic to construct fallback build settings for `build/Test.h` based on `include/Test.h`.
2026-03-23 17:23:54 +01:00
Paul LeMarquand 2814fa37ef Fix duplicate XCTest discovery for tests defined in extensions
When semantic test discovery encounters XCTest methods in an extension
it adds the extension definition to the root items list for each child
test method. With N test methods, the same extension root appears N
times, each copy receiving all N children. After merging, this produces
N*N test items instead of N.

The bug is normally masked by the syntactic index, which provides
correct results that take priority via `combineTests()`. This bug was
exposed while I was debugging why tests generated by build plugins would
appear multiple times. Turns out because they don't exist on disk at the
time of the syntatic scan only the semantic results are used, which
surfaced the issue.

The fix is to track already-added extension USRs to ensure each extension
added once as a root item.

Related issue: https://github.com/swiftlang/vscode-swift/issues/2162
2026-03-23 11:39:55 -04:00
Rintaro Ishizaki a9566ac183 [LSPAny] Replace manual LSPAnyCodable impl with Codable-backed default
Remove hand-written `init?(fromLSPDictionary:)` / `encodeToLSPAny()`
from LSPAnyCodable types, relying instead on the default implementations
backed by `LSPAnyEncoder`/`LSPAnyDecoder`
2026-03-22 08:01:17 -07:00
Rintaro Ishizaki 894496e9be Merge pull request #2549 from Tabonx/feature/codeAction-resolve-support 2026-03-22 06:11:21 -07:00
Pavel Kroupa 8639c19347 Add codeAction/resolve support 2026-03-21 10:38:44 +01:00
Rintaro Ishizaki 4435fe87d7 [TestDiscovery] Fix up test item ranges only in 'textDocument/tests'
Fixing up the ranges require 'textDocument/symbols' request, which needs
the document opened. But we don't want to open/close the documents just
for fixing up the ranges.
2026-03-07 00:43:31 -08:00
Rintaro Ishizaki 26f8efed5f [TestDiscovery] Use file modification time to filter semantic index
Instead of querying the index twice (once for up-to-date files, once for
outdated ones), collect file modification timestamps during the syntactic
scan phase and use them to filter a single semantic index query.
For files that don't support syntactic scans, use the semantic index
results even if outdated.

Also extracts symlink-aware mtime resolution into URL.fileModificationDate
and exposes snapshotHasInMemoryModifications(_:) on DocumentManager.
2026-03-06 15:33:19 -08:00
Rintaro Ishizaki 1c99daabef [TestDiscovery] Prefer syntactic scan results over semantic index
Previously, test discovery used the semantic index as the primary
source and fell back to the syntactic index only for files where the
semantic index was out-of-date. This meant test locations came from the
semantic index, which only records a point position rather than the
full symbol range.

Flip the priority: use syntactic scan results as the primary source
(which have correct location ranges) and supplement with semantic index
results. The semantic results are range-fixed via
'textDocument/documentSymbol' before being returned.

This logic is unified into a single 'combineTests' helper shared by
both 'workspaceTests' and 'documentTests'.

Also fix 'SyntacticSwiftXCTestScanner' to emit extensions as proper
'AnnotatedTestItem' nodes (with 'isExtension: true') rather than a flat
list of methods, so extension test methods are correctly merged into
their class via 'mergingTestsInExtensions'. The class and extension
visitors are unified through a shared 'handleClassOrExtension' helper.
2026-03-04 16:58:21 -08:00
Alex Hoppen ce86aae504 Merge pull request #2483 from ahoppen/explicitly-close-index 2026-03-01 08:18:19 +01:00
Steffeeen d748f80896 Implement support for textDocument/selectionRange
This enables hierarchical selection expansion in supported editors.

Selection ranges are computed from the AST by walking upward from the
smallest enclosing node to the root. This is implemented by AST nodes
conforming to the `SelectionRangeProvider` protocol. Most nodes use a
default implementation which returns the node's `trimmedRange`.
Other nodes are special-cased to adjust the returned selection ranges
based on other factors.
2026-02-26 09:15:01 +01:00
Alex Hoppen 425e1322a1 Explicitly close the index when shutting down SourceKit-LSP
`IndexStoreDB` moves its index to the `saved` directory when it is deallocated. Because `IndexStoreDB` is primarily owned by `UncheckedIndex`, we rely on deallocating this object to save the index store. This is fairly brittle because various parts of the codebase may hold transient references to that object as reported in https://github.com/swiftlang/sourcekit-lsp/issues/2455#issuecomment-3873561003.

Explicitly remove the reference from `UncheckedIndex` to `IndexStoreDB`. While this still isn’t perfect because other parts of the code base may hold references to `IndexStoreDB` but those should be a lot rarer, resulting in a more consistent closing of the index.
2026-02-15 18:02:53 +01:00
loveucifer 6028898c13 Optimize index usage for typeDefinition and inlay hint resolve requests. 2026-02-08 23:20:18 +05:30
loveucifer d73aba2c39 Remove duplicate definitionLocations and call shared function 2026-01-31 13:12:51 +05:30
loveucifer cccdde295c Use any LanguageService instead of closures 2026-01-30 02:47:52 +05:30