go: x/tools/gopls: add "implement missing function definition" quick fix

Is your feature request related to a problem? Please describe. It would be a QoL change, and save time(Javascript, C# and other vscode language extensions also have this feature).

Describe the solution you’d like When you want to call a function but it’s not yet defined and implemented, it would be nice that if you could choose from the context menu, to define the method or function. for example: go handleConnection(conn) then you click on the quick fixes content menu, and it automatically defines the function for you, like this: func handleConnection(conn net.Con) {}

Describe alternatives you’ve considered

Additional context Screenshot from 2021-08-05 14-04-49

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 9
  • Comments: 19 (15 by maintainers)

Commits related to this issue

Most upvoted comments

@enkeyz that’s something I personally would have done after this piece, to keep this relatively small and reasonable. Another thing I’d like to look at as well is returned values expected for the function, i.e.

var err error
err = myFunc() # undeclared myFunc

should generate

func myFunc() error {}

But again, as iterations on top of this.

So I’ve put together something that works (or seems to work). I’m probably gathering the data I need to generate those stubs in a poor manner, so please let me know how it can be improved.

I’ve added a bunch of test cases I used to validate what I was doing (still staying well away from any possible values an undeclared func might be intended to return).

For arguments names, if an identifier was used the name of that identifier is reused, otherwise names are inferred by the type of the argument, e.g.:

  • int -> i
  • error -> err
  • net.Conn -> conn
  • []int -> i

Also, if two arguments share the same identifier and/or type, argument name uniqueness is ensured, for example:

c("some", "strings")

// results in
func c(s1 string, s2 string) {}

For the sake of this conversation, I’m reporting below what code fixed by generating function stubs for each case looks like right now, so whoever is interested in checking the outputs doesn’t have to dive into code:

Test Cases

u is always the function that was undeclared to begin with.

Primitives with an identifier

package missingfunction

func a(s string) {
        u(s)
}

func u(s string) {}

Imported types

package missingfunction

import "io"

func a(r io.Reader) {
        u(r)
}

func u(r io.Reader) {}

Non-primitive types, values and pointers

package missingfunction

type T struct {}

func a() {
        pointer := &T{}
        var value T
        u(pointer, value)
}

func u(pointer *T, value T) {}

Non-unique identifiers

package missingfunction

func a(s string, i int) {
        u(s, i, s)
}

func u(s1 string, i int, s2 string) {}

Literals / No identifiers

package missingfunction

type T struct {}

func a() {
        u("hey compiler", T{}, &T{})
}

func u(s string, t1 T, t2 *T) {}

Returned values from another function

package missingfunction

import "io"

func a() {
        u(io.MultiReader())
}

func u(reader io.Reader) {}

Passing an error

package missingfunction

func a() {
        var err error
        u(err)
}

func u(err error) {}

Using a function with multiple returned values as an argument

package missingfunction

func a() {
        u(b())
}

func b() (string, error) {
        return "", nil
}

func u(s string, err error) {}

Using operations as arguments

package missingfunction

import "time"

func a() {
        u(10 * time.Second)
}

func u(duration time.Duration) {}

Using a slice as argument

package missingfunction

func a() {
        u([]int{1, 2})
}

func u(i []int) {}

If what’s there is actually usable/useful, what’s the plan now? 😃 also thanks for having me doing this, I’m having a blast!

@rentziass sounds good, please let us know how we can help.

@enkeyz just a year late, sorry 😅 not sure this is something you can solve, test code is still part of a package and depending on whether you’re using a _test package or not it might even be the same package as your non-test code.

@findleyr is it ok if I start looking into adding expected returned values too? After sometime spent as a user of this analyzer it really is a bit of a missing feature.

Thanks for adding this feature, but there’s one issue. When doing TDD, you write the tests first, so sometimes the function, or method doesn’t exists.

So when you use this auto implement feature, it creates the function or method in the test file, instead of the normal file, where you put the package code.

Is this something you can solve?

@rentziass Also, yeah, it should consider return values imo. Awesome job btw.

Change https://golang.org/cl/348829 mentions this issue: internal/lsp/analysis/implementmissing: add analyzer

Thanks for the suggestion. I agree that this would be helpful, and should theoretically not be that difficult to add.

Transferred to the Go issue tracker, as this would be implemented by Gopls.