golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.07k stars 17.68k forks source link

x/tools/gopls: disambiguate same method names in Call Hierarchy results #49690

Open ldelossa opened 2 years ago

ldelossa commented 2 years ago

What version of Go are you using (go version)?

$ go version
go version go1.17 linux/amd64

$ gopls version
golang.org/x/tools/gopls v0.7.2
    golang.org/x/tools/gopls@v0.7.2 h1:kRKKdvA8GOzra8rhSFDClOR7hV/x8v0J0Vm4C/gWq8s=

Does this issue reproduce with the latest release?

Using latest version

What operating system and processor architecture are you using (go env)?

go env Output
GO111MODULE=""
GOARCH="amd64"
GOBIN="/home/louis/git/gopath/bin"
GOCACHE="/home/louis/.cache/go-build"
GOENV="/home/louis/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/louis/git/gopath/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/louis/git/gopath"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"Each returned call hierarchy item should present itself as a unique 

GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17"
GCCGO="gccgo"
AR="ar"
CC="/usr/bin/clang"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2559996651=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I have a source file like this:

package main

type N struct{}

func (n *N) DoIt() {
    Func1()
}

type R struct{}

func (n *R) DoIt() {
    Func1()
}

func Func1() {
}

func Func4() {
    Func1()
    n := &N{}
    n.DoIt()
}

func main() {
    Func1()
}

I perform an "incoming calls" request on the symbol Func1 inside the main function.

Gopls returns this output (in lua table syntax, can assume the json)

{ {
    from = {
      detail = "github.com/ldelossa/calltree-nvim • main.go",
      kind = 12,
      name = "DoIt",
      range = {
        end = {
          character = 16,
          line = 4
        },
        start = {
          character = 12,
          line = 4
        }
      },
      selectionRange = {
        end = {
          character = 16,
          line = 4
        },
        start = {
          character = 12,
          line = 4
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    fromRanges = { {
        end = {
          character = 6,
          line = 5
        },
        start = {
          character = 1,
          line = 5
        }
      } }
  }, {
    from = {
      detail = "github.com/ldelossa/calltree-nvim • main.go",
      kind = 12,
      name = "DoIt",
      range = {
        end = {
          character = 16,
          line = 10
        },
        start = {
          character = 12,
          line = 10
        }
      },
      selectionRange = {
        end = {
          character = 16,
line = 10
        },
        start = {
          character = 12,
          line = 10
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    fromRanges = { {
        end = {
          character = 6,
          line = 11
        },
        start = {
          character = 1,
          line = 11
        }
      } }
  }, {
    from = {
      detail = "github.com/ldelossa/calltree-nvim • main.go",
      kind = 12,
      name = "Func4",
      range = {
        end = {
          character = 10,
          line = 17
        },
        start = {
          character = 5,
          line = 17
        }
      },
      selectionRange = {
        end = {
          character = 10,
          line = 17
        },
        start = {
          character = 5,
          line = 17
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    fromRanges = { {
        end = {
          character = 6,
          line = 18
        },
        start = {
          character = 1,
          line = 18
   line = 18
        }
      } }
  }, {
    from = {
      detail = "github.com/ldelossa/calltree-nvim • main.go",
      kind = 12,
      name = "main",
      range = {
        end = {
          character = 9,
          line = 23
        },
        start = {
          character = 5,
          line = 23
        }
      },
      selectionRange = {
        end = {
          character = 9,
          line = 23
        },
        start = {
          character = 5,
          line = 23
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    fromRanges = { {
        end = {
          character = 6,
          line = 24
        },
        start = {
          character = 1,
          line = 24
        }
      } }
  } }

As you can see both "DoIt" methods are shown with no details about the owning structure, or at least, the function's receiver.

What did you expect to see?

LSP call hierarchy items which represent methods should indicate their receivers/owning structures. This can be as simple as having the name field return "func (*R) DoIt" in my example.

What did you see instead?

Instead, gopls returns results which to the viewer/ui look ambiguous. Both returned "DoIt" functions make no mention that they are different functions with different owning structs.

ldelossa commented 2 years ago

Interestingly if you do a workspace symbol search based on the call hierarchy item name you get the following results:

    containerName = "github.com/ldelossa/calltree-nvim",
    kind = 6,
    location = {
      range = {
        end = {
          character = 16,
          line = 4
        },
        start = {
          character = 12,
          line = 4
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    name = "N.DoIt"
  }, {
    containerName = "github.com/ldelossa/calltree-nvim",
    kind = 6,
    location = {
      range = {
        end = {
          character = 16,
          line = 10
        },
        start = {
          character = 12,
          line = 10
        }
      },
      uri = "file:///home/louis/git/go/calltree.nvim/main.go"
    },
    name = "R.DoIt"
  } }

Would it be possible to use the same object identity (name,kind) so that a workspace symbol can be looked up from a call hierarchy item without ambiguity?

hyangah commented 2 years ago

Agree that it would be nice to share the symbol name presentation whenever possible - currently they don't share much.

Relevant code place: call hierarchy's name formatting