Skip to content
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: generate method stubs for a given interface #37537

Open
marwan-at-work opened this issue Feb 28, 2020 · 2 comments
Open

x/tools/gopls: generate method stubs for a given interface #37537

marwan-at-work opened this issue Feb 28, 2020 · 2 comments

Comments

@marwan-at-work
Copy link
Contributor

@marwan-at-work marwan-at-work commented Feb 28, 2020

Proposal (TL;DR):

It would be great if Gopls implemented a way where a user:

  1. Moves the cursor to a type declaration
  2. Gets a list of all interface declarations within the workspace
  3. Picks an interface for gopls to generate method stubs for.

See this video for a demonstration: https://vimeo.com/394345925

Details

A common feature that Go and other typed languages have is to generate method stubs for an interface that a type wants to implement.

For most languages, the concrete type must declare what interface it intends to implement. This makes it easier for tools to generate those stubs.

For an example, take a look at this screenshot from TypeScript in VSCode:

Screen Shot 2020-02-27 at 1 59 07 PM

Notice that type X implements Greeter and therefore the dropdown knows which method it needs to stub out.

In Go, it is impossible to know that because interfaces are implicitly implemented.

Therefore, generating method stubs require a two step process:

  1. You pick the interface declaration that you'd like an interface to implement
  2. You pick the concrete type you'd like to add method-stubs to.

Therefore, I wrote a tool that that can do both of these features: https://github.com/marwan-at-work/impl

Here's a video of how I integrated the tool with VSCode locally to demonstrate the same feature working for Go: https://vimeo.com/394345925

However, the tool uses go/packages directly and is obviously a standalone that doesn't leverage gopls with its cache and environment. Therefore, I suggest we make this a feature within gopls.

If this is something worth including, I'd be very happy to port the work I did into gopls (with a little help).

Unfortunately, the LSP protocol does not have an explicit message for "generating method stubs", and so we a few options were brought up in slack that I want to highlight here:

  1. Use CodeAction -> refactor.extract / quickfix
  2. Use noneStandardRequest
  3. Hacking around Autocomplete

cc: @stamblerre @hyangah -- I'm not sure which of the above is the best way, but I'm happy to take on whichever you think is best 👍

PS. Note that this tool used to exist in GOPATH mode using https://github.com/josharian/impl but as far as I know, it is not modules aware and lacked a number of features such as "listing available interfaces" and "automatically adding import paths"

@gopherbot gopherbot added this to the Unreleased milestone Feb 28, 2020
@gopherbot gopherbot added the Tools label Feb 28, 2020
@ianthehat

This comment has been minimized.

Copy link

@ianthehat ianthehat commented Feb 28, 2020

Another possibility would be to add it as a quick fix to the

*MyImplementation does not implement MyInterface (missing MyMethod method)

type checking error.
You could intentionally trigger it with the

var _ MyInterface = (*MyImplementation)(nil)

stanza if needed.
Not saying this is the best way, just adding it to the list for consideration.

@marwan-at-work

This comment has been minimized.

Copy link
Contributor Author

@marwan-at-work marwan-at-work commented Feb 28, 2020

@ianthehat Would it be possible to expand it to wherever a concrete type is being casted as an interface? For example:

function GetWriter() io.Writer {
  return &myWriter{} // quick fix: implement io.Writer on *myWriter
}

function takeReader(r io.Reader) { ... }

takeReader(&myReader{}) // quick fix: implement io.Reader on *myReader

Similar to rename, it should only do it if the concrete type was defined within the workspace/module boundaries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.