Skip to content

add go-to-definition for inlay hints (#2318)#2436

Merged
ahoppen merged 12 commits into
swiftlang:mainfrom
loveucifer:inlay-hint-go-to-definition
Jan 16, 2026
Merged

add go-to-definition for inlay hints (#2318)#2436
ahoppen merged 12 commits into
swiftlang:mainfrom
loveucifer:inlay-hint-go-to-definition

Conversation

@loveucifer
Copy link
Copy Markdown
Member

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

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 swiftlang#2318
XCTAssertEqual(parts.count, 1)
XCTAssertNotNil(parts.first?.location, "Expected label part to have location for go-to-definition")
} else if case .string = resolvedHint.label {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test only passes because we get into this case because there are no parts. AFAIK the problem is that the typeUSR field in the cursor info request isn’t actually a valid USR (looks like it hasn’t been used in a while). Furthermore, a purely USR-based implementation won’t be able to through the fallback locations in indexBasedDefinition and definitionLocations. In particular, it won’t be able to jump to a generated interface or jump to a definition if background indexing is disabled.

I think the correct implementation would be to extend the cursorinfo request to return line, column, filepath, module name and USR of the declaration’s type (maybe I forgot something else as well). The place to start debugging in order to do this would likely be https://github.com/swiftlang/swift/blob/f4e78a61dfbbaae7f1f03861d7ea8077546a4146/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp#L2736

The good news is that #548 would fall out for (almost) free and you would be able to fix the oldest open issue in this repo 😉

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm seems like im having a hard time figuring out how to go forward with this ( does this require me to work within the compiler i mean swift/swiftlang and handle edgecases and tests for those as well because thats gotta be long ig )

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if not ,i spent yesterday looking up fixes and found one ( idk if it works or has any more edgecases ) we could look up the type by its name string (e.g., "MyType") instead of the broken USR; it handles most casesig and would get this feature working immediately without me having to go through the compiler repo , that might take this pr a while , i mean i can do it but it will just take time maybe 2-4 days ig atleast to get fmailiar with the repo

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this require me to work within the compiler i mean swift/swiftlang

Yes, the entry barrier is definitely a little higher there but if you’re in for a challenge, I think you’d be up for it. If you get stuck somewhere, also feel free to just open a PR with how far you got and we can help you go on. I’d prefer to proper compiler-backed solution over something hacky in SourceKit-LSP because it will likely be a lot more error-resistant and easier to maintain.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey , i will try to learn the repo for a few days and try to fix the issue , should i convert this to a draft PR in the meantime

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, yes at some point you will need to know about sourcekitd when contributing to SourceKit-LSP. It’s where most of the actual semantic understanding meat is implemented. And because it’s a little harder to set up, those are the issues that don’t get tackled as quickly 😉

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will try and do my best :)

@loveucifer
Copy link
Copy Markdown
Member Author

loveucifer commented Jan 8, 2026

new commit requires swiftlang/swift#86381 for compiler changes

update inlay hint resolution to use the new type declaration location

fields from cursorInfo, with fallback to index lookup using the new

typeDeclUsr (a proper declaration USR).

Changes i made :

- Regenerated sourcekitd_uids.swift with new keys

- InlayHintResolve.swift: Try direct location first, fallback to index

- InlayHintTests.swift: Fixed test to properly verify location

This Requires: swift/swiftlang PR## #86381  for compiler changes
@loveucifer loveucifer force-pushed the inlay-hint-go-to-definition branch from bd7d3e0 to f46a31b Compare January 8, 2026 15:31
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 swiftlang#548
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 8, 2026

Very nice, I was expecting you to take longer to create a sourcekitd PR, good job 🌟

Let’s wait for swiftlang/swift#86381 to be approved and then I’ll review this PR in detail. Looked good from a first glance.

@loveucifer
Copy link
Copy Markdown
Member Author

Very nice, I was expecting you to take longer to create a sourcekitd PR, good job 🌟

yess i thought so too but i did have some previous experience with c++ while wriitng my game engine and I spent some time yesterday and today reading through the repo and thought might as well do it and learn more as i go on :D , thanks for your kind wordsss ❤️

@loveucifer
Copy link
Copy Markdown
Member Author

following the discussion in swiftlang/swift#86381. with hamishknight , ultimately reached the conclusion that we dont want any compiler changes , i am sending a pr that oughtta fix this but if not back to the compiler repo again we go :D

@loveucifer
Copy link
Copy Markdown
Member Author

as mentinoed above, i discovered that no changes are needed in the Swift repo. The existing cursorInfo already supports looking up types by USR via key.usr.
one of the key insight was that key.typeusr returned by cursorInfo is a mangled type name (e.g., $sSiD for Int), not a declaration USR. to use it for index lookup or cursorInfo queries
so :
replacing $s prefix with s: (e.g., $sSi → s:Si)
Strip trailing [D]suffix (type descriptor marker)
This converts the mangled type to a proper declaration USR that works with:

Index lookups via primaryDefinitionOrDeclarationOccurrence(ofUSR:)
cursorInfo queries via key.usr parameter
Implementation:

added convertMangledTypeToUSR() helper for the conversion
lookupTypeDefinitionLocation() tries index lookup first (fast path), falls back to cursorInfo for types not in index
should ideally work for both local project types and SDK/external types

also i closed the Swift repo PR #86381 as it's no longer needed.

Copy link
Copy Markdown
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhh, very nice that we can do this without modifying the cursor info request. I know about the USR-based cursor info but totally forgot about it again. I hope you still learned something worthwhile setting up you compiler development environment 😉


# Used exclusively within the SourceKit Plugin
KIND('DiagRemark', 'source.diagnostic.severity.remark'),
# Note: DiagRemark was moved to UID_KINDS in UIDs.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think this comment is providing any value. Let’s just remove it.

func definition(_ request: DefinitionRequest) async throws -> LocationsOrLocationLinksResponse?

func declaration(_ request: DeclarationRequest) async throws -> LocationsOrLocationLinksResponse?
func typeDefinition(_ request: TypeDefinitionRequest) async throws -> LocationsOrLocationLinksResponse?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think typeDefinition doesn’t have any tests at the moment yet. I would suggest we move its implementation to a follow-up PR and focus this one on the inlay hints.

}

func inlayHintResolve(_ req: InlayHintResolveRequest) async throws -> InlayHint {
// default: return hint unchanged
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think this comment provides much value, so I’d just remove it.

Comment on lines +1912 to +1913
// inlay hints store the uri in data for resolution
// extract uri from the lspany dictionary
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment on the comment here. This exactly explains what’s being done below, so I don’t think it provides much value. In general, I’m a fan of comments that describe why something is done, not what is being done.

Comment thread Sources/SwiftLanguageService/CursorInfo.swift Outdated
Comment thread Sources/SwiftLanguageService/InlayHintResolve.swift Outdated
Comment thread Sources/SwiftLanguageService/InlayHints.swift Outdated
Comment thread Tests/SourceKitLSPTests/InlayHintTests.swift Outdated
Comment thread Sources/SwiftLanguageService/InlayHintResolve.swift Outdated
Comment thread Tests/SourceKitLSPTests/InlayHintTests.swift
- 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
@loveucifer
Copy link
Copy Markdown
Member Author

I hope you still learned something worthwhile setting up you compiler development environment 😉

Yess totally and i bet it will come of use while fixing other issues ,i have noticed that some of the issues needs me to work within it so its good .

Comment on lines +221 to +224
// Strip trailing 'D' (type mangling suffix) to get declaration USR
if result.hasSuffix("D") {
result = String(result.dropLast())
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to do this, cursor info should be able to handle a type USR with it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm but the tests fail without the D stripping.

Copy link
Copy Markdown
Contributor

@hamishknight hamishknight Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting, I saw handling of Demangle::Node::Kind::Type in the code and assumed that was referring to D but it's actually a different kind. I guess this is okay for now but we really ought to fix this on the sourcekitd side, ideally at the same time as the $s -> s: change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okei

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to add my 2cts, while I’m not a huge fan, I’m fine with having the stripping of D as a temporary workaround for now as long as we try to adjust sourcekitd to work without this hack in the future.

Copy link
Copy Markdown
Member

@ahoppen ahoppen left a 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 inline. I think the best way forward might be:

  • Remove all remainders of the type definition request from this PR
  • Get this merged
  • Support jumping to a generated interface from inlay hints. I suspect that this might require some careful re-shuffling of code which might be easier to review if done on its own without having to worry the changes that are currently part of this PR. And this PR already provides great value on its own

Also, just want to express how extremely excited I am to use the type definition request once it gets in. I keep wanting that multiple times a week 🙂

Comment thread Sources/SwiftLanguageService/InlayHints.swift Outdated
Comment thread Sources/SwiftLanguageService/InlayHints.swift Outdated
Comment thread Tests/SourceKitLSPTests/InlayHintTests.swift Outdated
Comment thread Tests/SourceKitLSPTests/InlayHintTests.swift Outdated
Comment thread Tests/SourceKitLSPTests/InlayHintTests.swift Outdated
@loveucifer loveucifer force-pushed the inlay-hint-go-to-definition branch from c91c9d7 to 9e12af1 Compare January 11, 2026 11:10
@loveucifer
Copy link
Copy Markdown
Member Author

there is already a follow up PR in #2445 , should i include things that i left out here on that pr or work on an entirely new one ?

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 11, 2026

there is already a follow up PR in #2445 , should i include things that i left out here on that pr or work on an entirely new one ?

I just noticed that we eg. still have typeDefinition in LangaugeService. I’d pull that out of this PR and only add it in #2445, same for typeDefinitionProvider: .bool(true), not sure if there’s anything else.

Copy link
Copy Markdown
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to go, let’s just remove all references to typeDefinition from the diff.

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 12, 2026

@swift-ci Please test

@ahoppen ahoppen enabled auto-merge (squash) January 12, 2026 07:53
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 12, 2026

@swift-ci Please test Windows

@loveucifer
Copy link
Copy Markdown
Member Author

hmm failed ig 😵‍💫

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 12, 2026

swift-format validation failed with the following errors because the swift-format-ignore lines were removed

+ /Users/ec2-user/jenkins/workspace/swift-sourcekit-lsp-PR-macOS/branch-main/build/buildbot_incremental/unified-swiftpm-build-macosx-x86_64/release/swift-format lint --parallel --strict --recursive /Users/ec2-user/jenkins/workspace/swift-sourcekit-lsp-PR-macOS/branch-main/sourcekit-lsp
branch-main/sourcekit-lsp/Sources/SourceKitD/sourcekitd_uids.swift:17:16: error: [TypeNamesShouldBeCapitalized] rename the struct 'sourcekitd_api_keys' using UpperCamelCase; for example, 'Sourcekitd_api_keys'
branch-main/sourcekit-lsp/Sources/SourceKitD/sourcekitd_uids.swift:794:16: error: [TypeNamesShouldBeCapitalized] rename the struct 'sourcekitd_api_requests' using UpperCamelCase; for example, 'Sourcekitd_api_requests'
branch-main/sourcekit-lsp/Sources/SourceKitD/sourcekitd_uids.swift:968:16: error: [TypeNamesShouldBeCapitalized] rename the struct 'sourcekitd_api_values' using UpperCamelCase; for example, 'Sourcekitd_api_values'
ERROR: command `['/Users/ec2-user/jenkins/workspace/swift-sourcekit-lsp-PR-macOS/branch-main/build/buildbot_incremental/unified-swiftpm-build-macosx-x86_64/release/swift-format', 'lint', '--parallel', '--strict', '--recursive', '/Users/ec2-user/jenkins/workspace/swift-sourcekit-lsp-PR-macOS/branch-main/sourcekit-lsp']` terminated with a non-zero exit status 1, aborting

Could you add them back in, ideally in a way that they don’t get removed when re-generating the file 😉

auto-merge was automatically disabled January 12, 2026 12:32

Head branch was pushed to by a user without write access

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 12, 2026

@swift-ci Please test

@ahoppen ahoppen enabled auto-merge January 12, 2026 13:33
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 12, 2026

@swift-ci Please test Windows

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add this file to CMakeLists.txt to make the tests pass on Windows?

auto-merge was automatically disabled January 13, 2026 02:06

Head branch was pushed to by a user without write access

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 13, 2026

@swift-ci Please test

1 similar comment
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 13, 2026

@swift-ci Please test

@loveucifer
Copy link
Copy Markdown
Member Author

hmm another macos fail :/

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 14, 2026

Failures is unrelated. Let’s try again.

@swift-ci Please test macOS

@loveucifer
Copy link
Copy Markdown
Member Author

hmm failed again ig

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 14, 2026

Oh, interesting. Almost all the tests failed with error: Exited with unexpected signal code <random signal here>. No idea how that happens. Let’s try again to see if it’s infrastructure or your PR.

@swift-ci Please test macOS

@loveucifer
Copy link
Copy Markdown
Member Author

Oh lol , lets see also i did apply for the member program , been 6 days didnt hear back seems like not upto it :/

@PhantomInTheWire
Copy link
Copy Markdown
Member

seems like a github issue again @swift-ci please test macos

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 15, 2026

Looking through the logs after the --- Running tests in parallel failed. Re-running tests serially to capture more actionable output. marker, I noticed the following:

We are seeing a sourcekitd crash in testCodeCompletionShowsUpdatedResultsAfterDependencyUpdated, which we really shouldn’t because this is not a test that tests crash recovery of sourcekitd. It’s also the first time that we invoke code completion in the tests, so this is likely an issue with the SourceKit plugin. But even though sourcekitd crashes (which is an XPC service), it shouldn’t take down the SourceKit-LSP test runner itself.

I tested if this might have been introduced by a recent change in SwiftPM but have been unable to reproduce the issue by building SwiftPM from source so far. I’m now testing if this issue is caused by changes in this PR (which I can’t really believe) or if it’s caused by something else by re-triggering CI on #2450. I fear this will boil down to having to build an entire toolchain locally and trying to reproduce it that way.

All that is to say, I’ll take care of it and come back once I know more.

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 15, 2026

Update: Also seeing the same failure in swiftlang/indexstore-db#276, so it’s not related to this PR. Now the debugging fun begins.

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 16, 2026

Crash should be fixed by: swiftlang/swift#86583. Let's try again.

@swift-ci Please test macOS

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 16, 2026

@swift-ci Please test macOS

@ahoppen ahoppen merged commit 61ba0c9 into swiftlang:main Jan 16, 2026
3 checks passed
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Jan 16, 2026

Finally 🎉🎉🎉

When you have time, do you mind rebasing the type definition PR and I'll review it next.

@loveucifer
Copy link
Copy Markdown
Member Author

Finally 🎉🎉🎉

When you have time, do you mind rebasing the type definition PR and I'll review it next.

doing it rn hold on :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants