Skip to content

x/tools/gopls: resolve imports with name collisions and let the user customize aliases #74918

@cespare

Description

@cespare

gopls version

Build info
----------
golang.org/x/tools/gopls v0.20.0
    golang.org/x/tools/[email protected] h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4=
    github.com/BurntSushi/[email protected] h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
    github.com/fatih/[email protected] h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
    github.com/fatih/[email protected] h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg=
    github.com/fatih/[email protected] h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
    github.com/fsnotify/[email protected] h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
    github.com/google/[email protected] h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
    golang.org/x/exp/[email protected] h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
    golang.org/x/[email protected] h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
    golang.org/x/[email protected] h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
    golang.org/x/[email protected] h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
    golang.org/x/[email protected] h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
    golang.org/x/[email protected] h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
    golang.org/x/[email protected] h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM=
    golang.org/x/[email protected] h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
    honnef.co/go/[email protected] h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw=
    mvdan.cc/[email protected] h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
    mvdan.cc/xurls/[email protected] h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
go: go1.24.6

go env

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN='/home/caleb/bin'
GOCACHE='/home/caleb/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/caleb/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3694712078=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/caleb/w/liftoff/go.mod'
GOMODCACHE='/home/caleb/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/caleb/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/caleb/3p/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/caleb/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/caleb/3p/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

(This seems very similar to, or perhaps a dupe of, #40278, judging by the description. However, gopls definitely doesn't seem to do what is described there.)

It's unfortunately quite common that I need to deal with packages with name collisions. The main offender is cmp and github.com/google/go-cmp/cmp, though there are some others as well.

When I encounter this situation, gopls is much less helpful than it normally is when dealing with non-colliding packages:

  • Once I've imported one package, I can't get completions about names for the other package.
  • Once I've imported one package, gopls doesn't add the colliding package import. I need to manually add the import with an alias.

Here is a concrete scenario: I create a file that imports cmp. (Let's say it uses cmp.Or somewhere.)

What did you see happen?

If I type cmp. and then invoke completion, I only get suggestions from the stdlib's cmp package. If I type cmp.Di and invoke completion, there are no suggestions, even though go-cmp is a dependency of my module. If I type cmp.Diff and hit save, it's just a compile error; no import is added.

What did you expect to see?

It would be nice if gopls helped me here. For example:

  • If I type cmp.Di, it could show me Diff as a completion since that's available from a different cmp than the cmp I already have imported into my package.
  • If I type cmp.Diff and hit save, it could realize that because I'm referring to a different cmp than the one I've imported, it should import github.com/google/go-cmp/cmp, give it an alias (say gocmp), and then change my text to gocmp.Diff.

There are probably some other ways for this UX to work. I'd just like to avoid needing to manually add the import and alias.

Furthermore, I'd like to be able to provide gopls with my preferences about standard collision resolution. When cmp and github.com/google/go-cmp/cmp are both imported, I always want the latter to be aliased as gocmp, regardless of which import was added first.

Editor and settings

I'm using neovim and its LSP support.

Logs

This is a feature request, not a bug report, but I can capture logs if you want. There's nothing interesting or unexpected there AFAICT.

Metadata

Metadata

Assignees

Labels

FeatureRequestIssues asking for a new feature that does not need a proposal.ToolsThis label describes issues relating to any tools in the x/tools repository.goplsIssues related to the Go language server, gopls.gopls/imports

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions