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
x/tools/gopls: jump to function definition via go:linkname #57312
Comments
Thanks, this is an interesting idea, which I think could be feasible. Transferring to the go issue as this would be implemented in gopls. |
Hi, I'd like to give this a try. I made a first attempt (without My idea was that a map of all links can be created ahead of time (and cached?), then used when analyzing a single file to decorate any decls that are part of a "link". How would this work in |
Hi @vikblom, thanks for looking into this! Sorry for the slow response: had to do a bit of research to be able to make an informed response. The compiler documentation for linkname is lacking (@adonovan is currently updating it in https://go.dev/cl/463136!), but I think we need to identify two different patterns for using In this playground link, where package
In bar, use a
In foo, use a
I think we need to treat these two cases differently from gopls: Handling pattern (1): (1) it is pretty straightforward how to find the symbol: in order to jump from Handling pattern (2) is more complicated: in order to jump from I think pattern 1 is far more common than pattern 2, and so it would be OK to only implement support for pattern 1 in the initial implementation. I don't think we should have to manage a linkname index. It would be simpler to just look through the forward dependencies of packages containing the The way to do this in gopls is to first find package information for packages containing the given file: Since metadata and type-checked packages are cached, these should be cache hits most of the time, and therefore it should be fine to implement the search in this way, without any need for additional caching. Sorry for the wall of text. Does that make sense? |
Thank you @findleyr that makes a lot of sense A note on pattern 2, as I understand it, But anyway, aiming for pattern 1 first seems like a good approach, I will start there. Should this extend "goto definition" or be some kind of navigable hyperlink? If you have a package in mind where this should be implemented that would be helpful. |
Oh, interesting. Thank you, that makes sense. I actually tested exactly that, and saw the compiler error. I did not think of adding a .s file.
I think eventually it would be good to handle a variety of requests related to linknames, but let's start with handling the At that link, gopls delegates to a source.Identifier function to collect information about the identifier at point. This function collects a bunch of information about the identifier at the current cursor position, most of which is not applicable for the case we're considering. (Frankly, Something like this: // At internal/lsp/definition.go:25:
if pkgPath, name := source.ParseLinkname(ctx, snapshot, fh, params.Position); pkgPath != "" {
return source.FindLinkname(ctx, snapshot, fh, pkgPath, name)
}
// Otherwise, proceed as before
ident, err := source.Identifier(...)
// In the internal/lsp/source package:
// ParseLinkname attempts to parse a go:linkname declaration at the given pos.
// If successful, it returns the package path and object name referenced by the second
// argument of the linkname directive.
//
// If the position is not in a go:linkname directive, or parsing fails, it returns "", "".
func ParseLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (pkgPath, name string)
// FindLinkname searches dependencies of packages containing fh for an object
// with linker name matching the given package path and name.
func FindLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position, pkgPath, name string) ([]protocol.Location, error) In other words, just intercept the definition request and check whether this new linkname logic applies, before passing off to the normal handling. You can either use In In this way, I think this project can be implemented without having to get too far into the weeds. You don't have to take my suggested API, but I would just advise keeping your change isolated from the existing logic. |
Keeping the changes isolated sounds like a good idea I will put some effort into this (could take some time) and post back here when I have an update (or questions). |
Thanks @vikblom! This issue is not particularly urgent, but I have added you as assignee. Feel free to ping back here if you have any questions as you work on this. |
Change https://go.dev/cl/463755 mentions this issue: |
For reference, I had a quick look at the standard library for examples. I found directives at: Pattern 1
https://cs.opensource.google/go/go/+/master:src/time/time.go;l=1099 Pattern 2
https://cs.opensource.google/go/go/+/master:src/runtime/mheap.go;l=1654 Edit: I wrote a script to walk through the standard library, checking if linkname directives (1st argument) funcs are with or without bodies, and if the referenced package (2nd argument) is a forward or reverse dependency. The numbers are
|
Is your feature request related to a problem? Please describe.
//go:linkname
is one method to export one function as a different name or path.I think we should support the jumping to/back navigation, it will be much more convenient to read the source code, especially go source.
Describe the solution you'd like
Go AST parser extracts this go:linkname directives and generate navigation link.
When user hovers on the function name, it display a link, so user can ctrl+click to jump to the definition location.
Describe alternatives you've considered
No alternatives considered now.
Additional context
No additional context now.
The text was updated successfully, but these errors were encountered: