-
Notifications
You must be signed in to change notification settings - Fork 326
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.
| } else { | ||
| name = "\(symbol.name): \(conformances.map(\.symbol.name).sorted().joined(separator: ", "))" | ||
| } | ||
| switch symbol.kind { |
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.
This looks like incorrect indentation to me. Could you run swift-format on your change?
| // Add the file name and line to the detail string | ||
| if let url = remappedLocation.uri.fileURL, | ||
| let basename = (try? AbsolutePath(validating: url.filePath))?.basename | ||
| { | ||
| detail = "Extension at \(basename):\(remappedLocation.range.lowerBound.line + 1)" | ||
| } else if !definition.location.moduleName.isEmpty { | ||
| detail = "Extension in \(definition.location.moduleName)" | ||
| } else { | ||
| detail = "Extension" | ||
| } |
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.
Did you unintentionally duplicate this code?
| detail = info.location.moduleName | ||
| } | ||
|
|
||
| let item = TypeHierarchyItem( |
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.
Shouldn’t we be able to just all into the adjust method for TypeHierarchyItem here and not have these 40-ish lines of adjustment code? Same for the other TypeHierarchyItem returning functions.
oh cool I will try to fix , this was my first time contributing to swift :) |
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.
| return edit | ||
| } | ||
|
|
||
| package func locationsOrLocationLinksAdjustedForCopiedFiles(_ response: LocationsOrLocationLinksResponse?) -> LocationsOrLocationLinksResponse? { |
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.
Could your run swift-format on your changes? https://github.com/swiftlang/sourcekit-lsp/blob/main/CONTRIBUTING.md#formatting
| ) | ||
| } | ||
|
|
||
| private func callHierarchyItemAdjustedForCopiedFiles( |
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.
Shouldn’t this be a method on BuildServerManager like the other methods that adjust for copied files?
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.
| ) | ||
| return Location(uri: symbolOccurrence.location.documentUri, range: Range(symbolPosition)) | ||
| } | ||
| let remappedLocations = await workspace.buildServerManager.locationsAdjustedForCopiedFiles(locations) |
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.
Do we need to store the mapped location here? Wouldn’t it be easier if we just call await workspace.buildServerManager.locationsAdjustedForCopiedFiles inside symbolsAndIndex.sorted(by: { $0.symbol < $1.symbol }).map where we currently have let symbolLocation = Location?
| // for C/C++/objC functions with separate declaration and definition, | ||
| // "implementation" means the definition. Only use this fallback if there's | ||
| // a declaration without a definition at the same location. | ||
| if occurrences.isEmpty { | ||
| let declarations = index.occurrences(ofUSR: usr, roles: .declaration) | ||
| let definitions = index.occurrences(ofUSR: usr, roles: .definition) | ||
| // check if there are declarations that don't have a definition at the same location | ||
| let hasDeclarationOnlyLocations = declarations.contains { decl in | ||
| !definitions.contains { def in | ||
| def.location.path == decl.location.path && def.location.line == decl.location.line | ||
| } | ||
| } | ||
| if hasDeclarationOnlyLocations { | ||
| occurrences = definitions | ||
| } | ||
| } |
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.
Is this change unrelated to the copied file mapping? If so, could you open a separate PR for it?
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.
I think this is needed because the testFindImplementationInCopiedHeader - without it the test fails because C functions need this fallback to find the definition from a declaration , the tests kept failing without it i think the error was something like "Go to Implementation" on a C function returning empty because C functions don't have the inheritance relationships i might be wrong but now that i tried without using this the tests failed again : /
| var callHierarchyItems: [CallHierarchyItem] = [] | ||
| for usr in usrs { |
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.
Is there any particular reason why you switched from the compactMap based implementation to for … in? I’d prefer if we just sticked with the old compactMap-based approach. It it was to allow await calls in the body, we have the asyncCompactMap helper for that.
Same for the other locations where you switched from compactMap to for … in
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.
The original change to for...in was because we needed await for the location remappingand stuff . I didn't quite think about asyncCompactMap at the time idk might've missed it my bad. I've now switched them all back to use asyncCompactMap changing all of them soon :D
| { | ||
| detail = "Extension at \(basename):\(location.range.lowerBound.line + 1)" | ||
| } else if let moduleName = moduleName { | ||
| } else if let moduleName = moduleName, !moduleName.isEmpty { |
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.
Is this change unrelated to the PR? Could you open a separate PR for it, so we can give this change its own dedicated discussion?
| // TODO: Remove this workaround once https://github.com/swiftlang/swift/issues/75600 is fixed | ||
| func indexToLSPLocation2(_ location: SymbolLocation) -> Location? { | ||
| return self.indexToLSPLocation(location) | ||
| } | ||
|
|
||
| // TODO: Remove this workaround once https://github.com/swiftlang/swift/issues/75600 is fixed | ||
| func indexToLSPTypeHierarchyItem2( | ||
| definition: SymbolOccurrence, | ||
| moduleName: String?, | ||
| index: CheckedIndex | ||
| ) -> TypeHierarchyItem? { | ||
| return self.indexToLSPTypeHierarchyItem( | ||
| definition: definition, | ||
| moduleName: moduleName, | ||
| index: index | ||
| ) | ||
| } |
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.
It seems that these workarounds might indeed no longer needed when using Swift 6.3 snapshots but the issue does still persist in Swift 6.2. Since SourceKit-LSP still needs to compile using the released Swift 6.2 compiler, we still need them.
Even if the changes were no longer needed, I’d prefer to remove the workarounds in a separate PR.
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.