-
Notifications
You must be signed in to change notification settings - Fork 327
Extend copied file mapping to all LSP requests returning locations #2385
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
base: main
Are you sure you want to change the base?
Extend copied file mapping to all LSP requests returning locations #2385
Conversation
This addresses issue swiftlang#2276 by ensuring that all LSP requests that return source file locations map copied header files back to their original locations, not just jump-to-definition. Previously, only the definition request applied this mapping. Now, the following requests also adjust locations for copied files: - textDocument/references - textDocument/implementation - workspace/symbol - callHierarchy/prepare - callHierarchy/incomingCalls - callHierarchy/outgoingCalls - typeHierarchy/prepare - typeHierarchy/supertypes - typeHierarchy/subtypes This provides consistent navigation behavior, ensuring users are always taken to the original source files instead of build artifacts when possible.
4fba69c to
70d900e
Compare
ahoppen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool 🤩 Excited to see this! I left a few comments inline.
c4f0eb2 to
70d900e
Compare
- Remove async from workspaceEditAdjustedForCopiedFiles - Refactor to use uriAdjustedForCopiedFiles helper - Update dictionary update logic with += - Adjust LocationLink creation to use adjusted ranges - Ensure selectionRange adjustment in prepareCallHierarchy - Provide default WorkspaceEdit in ClangLanguageService - Revert asyncMap to map and remove await in SourceKitLSPServer - Chain workspace and index retrieval in incomingCalls - Use indexToLSPCallHierarchyItem and shared helper for CallHierarchyItem - Fix indentation and remove duplicated detail setting - Use shared helper for TypeHierarchyItem - Remove .sort() from expected array in tests - Enable testFindImplementationInCopiedHeader - Add await for actor-isolated BuildServerManager calls
df65d94 to
cae01c6
Compare
- Refactor supertypes/subtypes to use indexToLSPTypeHierarchyItem helper instead of duplicating ~80 lines of TypeHierarchyItem creation code - Remove unused workaround helper functions (indexToLSPLocation2, indexToLSPTypeHierarchyItem2) - Fix test ordering: use deterministic sorted order instead of Set comparison - Enable testFindImplementationInCopiedHeader test - Add implementation request support for C/C++/ObjC functions with separate declaration and definition (finds definition when declarations exist without definitions at the same location) - Fix whitespace/indentation issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR extends the remapping of copied header files to their original source locations across all LSP requests that return location information. Previously, only the textDocument/definition request applied this mapping; now all location-returning requests (references, implementation, workspace symbols, call hierarchy, and type hierarchy) consistently navigate users to original source files instead of build artifacts.
Key Changes:
- Added location remapping to references, implementation, and workspace symbol requests
- Implemented location remapping in call hierarchy (prepare, incoming, outgoing) operations
- Implemented location remapping in type hierarchy (prepare, supertypes, subtypes) operations
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Tests/SourceKitLSPTests/CopiedHeaderTests.swift | New test file covering references, implementation, declaration, and workspace symbols in copied headers |
| Sources/SourceKitLSP/SourceKitLSPServer.swift | Extended location remapping to all LSP location-returning requests and refactored call/type hierarchy handling |
| Sources/ClangLanguageService/ClangLanguageService.swift | Added location remapping for declaration and rename requests |
| Sources/BuildServerIntegration/BuildServerManager.swift | Added helper methods for remapping locations in workspace edits, location links, and type hierarchy items |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
hey @ahoppen can i get another review :) |
ahoppen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I left two more comments inline but I think a few of my last comments are still outstanding (see the ones that I didn’t mark as resolved). In particular, I don’t think that SourceKitLSPServer.swift should contain any large-scale edits for this change, it should just call to adjust methods in BuildServerManager to take copied files into account.
got it thanks ! |
ahoppen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update. The PR looks pretty good now, I left a few more stylistic-ish comments inline.
ahoppen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few more comments in the PR to simplify the diff a little further, but otherwise looks good to me.
ahoppen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks great to me. Thanks for addressing this issue 😍
|
@swift-ci Please test |
|
@swift-ci Please test Windows |
Thanks! This was my first contribution to Swift, and I loved the whole PR process |
|
(I'm asking around about the compiler crashes) |
|
I preserved the current state in https://github.com/rintaro/sourcekit-lsp/tree/PR-2385-crasher so compiler folks can look into it. |
|
I filed swiftlang/swift#86170 for the compiler crash. A workaround seems to be to refer to diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift
index 80055d84..c92b7c68 100644
--- a/Sources/SourceKitLSP/SourceKitLSPServer.swift
+++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift
@@ -2546,7 +2546,8 @@ extension SourceKitLSPServer {
)
}
- let typeHierarchyItems = await usrs.asyncCompactMap { (usr) -> TypeHierarchyItem? in
+ var typeHierarchyItems: [TypeHierarchyItem] = []
+ for usr in usrs {
guard let info = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: usr) else {
return nil
}
@@ -2570,8 +2571,9 @@ extension SourceKitLSPServer {
guard let item = indexToLSPTypeHierarchyItem2(definition: info, moduleName: moduleName, index: index) else {
return nil
}
- return await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item)
- }.sorted(by: { $0.name < $1.name })
+ typeHierarchyItems.append(await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item))
+ }
+ typeHierarchyItems.sort(by: { $0.name < $1.name })
if typeHierarchyItems.isEmpty {
// When returning an empty array, VS Code fails with the following two errors. Returning `nil` works around those |
got it doing it rn |
|
hey @ahoppen sorry if this is the wrong place to ask is there a server or communication channel for this repo |
|
@swift-ci Please test |
For anything that’s related to a specific issue or a code change, GitHub is really the best communication channel. For anything more broad, you can also post in the SourceKit-LSP category on the Swift Forums. |
|
seems like its still failing :( |
|
Looks like we need to apply the same trick in a couple new places. It builds with the following diff applied using Diffdiff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift
index dbf4896f..3542baf1 100644
--- a/Sources/SourceKitLSP/SourceKitLSPServer.swift
+++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift
@@ -2281,15 +2281,17 @@ extension SourceKitLSPServer {
// Only return a single call hierarchy item. Returning multiple doesn't make sense because they will all have the
// same USR (because we query them by USR) and will thus expand to the exact same call hierarchy.
- let callHierarchyItems = await usrs.asyncCompactMap { (usr) -> CallHierarchyItem? in
+ var callHierarchyItems: [CallHierarchyItem] = []
+ for usr in usrs {
guard let definition = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: usr) else {
- return nil
+ continue
}
guard let item = indexToLSPCallHierarchyItem2(definition: definition, index: index) else {
- return nil
+ continue
}
- return await workspace.buildServerManager.callHierarchyItemAdjustedForCopiedFiles(item)
- }.sorted(by: { Location(uri: $0.uri, range: $0.range) < Location(uri: $1.uri, range: $1.range) })
+ callHierarchyItems.append(await workspace.buildServerManager.callHierarchyItemAdjustedForCopiedFiles(item))
+ }
+ callHierarchyItems.sort(by: { Location(uri: $0.uri, range: $0.range) < Location(uri: $1.uri, range: $1.range) })
// Ideally, we should show multiple symbols. But VS Code fails to display call hierarchies with multiple root items,
// failing with `Cannot read properties of undefined (reading 'map')`. Pick the first one.
@@ -2358,24 +2360,25 @@ extension SourceKitLSPServer {
return self.indexToLSPCallHierarchyItem(definition: definition, index: index)
}
- let calls = await callersToCalls.asyncCompactMap { (caller, callsList) -> CallHierarchyIncomingCall? in
+ var calls: [CallHierarchyIncomingCall] = []
+ for (caller, callsList) in callersToCalls {
// Resolve the caller's definition to find its location
guard let definition = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: caller.usr) else {
- return nil
+ continue
}
let locations = callsList.compactMap { indexToLSPLocation2($0.location) }.sorted()
let remappedLocations = await workspace.buildServerManager.locationsAdjustedForCopiedFiles(locations)
guard !remappedLocations.isEmpty else {
- return nil
+ continue
}
guard let item = indexToLSPCallHierarchyItem2(definition: definition, index: index) else {
- return nil
+ continue
}
let remappedItem = await workspace.buildServerManager.callHierarchyItemAdjustedForCopiedFiles(item)
- return CallHierarchyIncomingCall(from: remappedItem, fromRanges: remappedLocations.map(\.range))
+ calls.append(CallHierarchyIncomingCall(from: remappedItem, fromRanges: remappedLocations.map(\.range)))
}
return calls.sorted(by: { $0.from.name < $1.from.name })
}
@@ -2404,26 +2407,27 @@ extension SourceKitLSPServer {
let callableUsrs = [data.usr] + index.occurrences(relatedToUSR: data.usr, roles: .accessorOf).map(\.symbol.usr)
let callOccurrences = callableUsrs.flatMap { index.occurrences(relatedToUSR: $0, roles: .containedBy) }
.filter(\.shouldShowInCallHierarchy)
- let calls = await callOccurrences.asyncCompactMap { occurrence -> CallHierarchyOutgoingCall? in
+ var calls: [CallHierarchyOutgoingCall] = []
+ for occurrence in callOccurrences {
guard occurrence.symbol.kind.isCallable else {
- return nil
+ continue
}
guard let location = indexToLSPLocation2(occurrence.location) else {
- return nil
+ continue
}
let remappedLocation = await workspace.buildServerManager.locationAdjustedForCopiedFiles(location)
// Resolve the callee's definition to find its location
guard let definition = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: occurrence.symbol.usr) else {
- return nil
+ continue
}
guard let item = indexToLSPCallHierarchyItem2(definition: definition, index: index) else {
- return nil
+ continue
}
let remappedItem = await workspace.buildServerManager.callHierarchyItemAdjustedForCopiedFiles(item)
- return CallHierarchyOutgoingCall(to: remappedItem, fromRanges: [remappedLocation.range])
+ calls.append(CallHierarchyOutgoingCall(to: remappedItem, fromRanges: [remappedLocation.range]))
}
return calls.sorted(by: { $0.to.name < $1.to.name })
}
@@ -2624,17 +2628,18 @@ extension SourceKitLSPServer {
// Convert occurrences to type hierarchy items
let occurs = baseOccurs + retroactiveConformanceOccurs
- let types = await occurs.asyncCompactMap { occurrence -> TypeHierarchyItem? in
+ var types: [TypeHierarchyItem] = []
+ for occurrence in occurs {
// Resolve the supertype's definition to find its location
guard let definition = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: occurrence.symbol.usr) else {
- return nil
+ continue
}
let moduleName = definition.location.moduleName
guard let item = indexToLSPTypeHierarchyItem2(definition: definition, moduleName: moduleName, index: index) else {
- return nil
+ continue
}
- return await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item)
+ types.append(await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item))
}
return types.sorted(by: { $0.name < $1.name })
}
@@ -2664,7 +2669,8 @@ extension SourceKitLSPServer {
}
// Convert occurrences to type hierarchy items
- let types = await occurs.asyncCompactMap { occurrence -> TypeHierarchyItem? in
+ var types: [TypeHierarchyItem] = []
+ for occurrence in occurs {
if occurrence.relations.count > 1 {
// An occurrence with a `baseOf` or `extendedBy` relation is an occurrence inside an inheritance clause.
// Such an occurrence can only be the source of a single type, namely the one that the inheritance clause belongs
@@ -2672,19 +2678,19 @@ extension SourceKitLSPServer {
logger.fault("Expected at most extendedBy or baseOf relation but got \(occurrence.relations.count)")
}
guard let related = occurrence.relations.sorted().first else {
- return nil
+ continue
}
// Resolve the subtype's definition to find its location
guard let definition = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: related.symbol.usr) else {
- return nil
+ continue
}
let moduleName = definition.location.moduleName
guard let item = indexToLSPTypeHierarchyItem2(definition: definition, moduleName: moduleName, index: index) else {
- return nil
+ continue
}
- return await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item)
+ types.append(await workspace.buildServerManager.typeHierarchyItemAdjustedForCopiedFiles(item))
}
return types.sorted { $0.name < $1.name }
} |
|
@ahoppen hope this fixes it :3 |
|
@swift-ci Please test |
This addresses issue #2276 by ensuring that all LSP requests that return source file locations map copied header files back to their original locations, not just jump-to-definition.
Previously, only the definition request applied this mapping. Now, the following requests also adjust locations for copied files:
This provides consistent navigation behavior, ensuring users are always taken to the original source files instead of build artifacts when possible.