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.
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.
- **`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).
`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`.
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.
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.
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.
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`.
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.
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.
`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.
- Use cursorInfo USR lookup instead of index (more accurate)
- Add document version tracking to reject stale resolve requests
- Make InlayHintResolveData conform to LSPAnyCodable
- Reference swiftlang/swift#86432 for mangled type workaround
- cursorInfoFromTypeUSR takes DocumentSnapshot for version safety
- Remove TypeDefinition.swift (defer to follow-up PR)
- Remove unnecessary comments
- Tests work without index
Add support for the textDocument/typeDefinition LSP request, which
finds the type of the symbol at a given position and returns the
location of that type's definition.
This uses the same type definition lookup mechanism as the inlay hint
resolution feature, which queries cursorInfo for the new type
declaration location fields (typeDeclFilePath/Line/Column) with
fallback to index lookup using typeDeclUsr.
Fixes#548
Implements resolveProvider for inlay hints to enable navigating to type
definitions. When an inlay hint showing a type is resolved, the server
looks up the type's definition location using cursorInfo and the index.
- store variable position in InlayHint.data for resolution
- add inlayHintResolve to LanguageService protocol
- implement resolve handler using cursorInfo and index lookup
- enable resolveProvider: true in capabilities
- add test for resolve functionality
Addresses #2318
Shut down language services when a workspace is closed
- Added allLanguageServices property to Workspace to get all services it references
- Added shutdownOrphanedLanguageServices to clean up services no longer in use
- When workspace folders are removed, we now shut down their associated language services
- This properly terminates clangd and other language server processes when workspaces close