Skip to content

Renaming interface method does not propagate change to implementing types #2275

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

Open
vlymar opened this issue Jun 3, 2022 · 6 comments
Open
Labels
gopls/refactoring refactoring related issues gopls gopls related issues

Comments

@vlymar
Copy link

vlymar commented Jun 3, 2022

What version of Go, VS Code & VS Code Go extension are you using?

Version Information
  • Run go version to get version of Go from the VS Code integrated terminal.
    • go version go1.18.1 darwin/arm64
  • Run gopls -v version to get version of Gopls from the VS Code integrated terminal.
    • golang.org/x/tools/gopls v0.8.4
  • Run code -v or code-insiders -v to get version of VS Code or VS Code Insiders.
    • Version: 1.66.2
  • Check your installed extensions to get the version of the VS Code Go extension
    • v0.33.1
  • Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > Go: Locate Configured Go Tools command.
Checking configured tools....
GOBIN: undefined
toolsGopath: 
gopath: /Users/victor/go/1.18.1
GOROOT: /Users/victor/.goenv/versions/1.18.1
PATH: /Users/victor/.goenv/versions/1.18.1/bin:/Users/victor/.sdkman/candidates/sbt/current/bin:/Users/victor/.sdkman/candidates/java/current/bin:/opt/homebrew/Cellar/zplug/2.4.2/bin:/Users/victor/.goenv/shims:/Users/victor/.goenv/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki:/Users/victor/go/1.18.1/bin:/opt/homebrew/opt/fzf/bin
PATH (vscode launched with): /Users/victor/.sdkman/candidates/sbt/current/bin:/Users/victor/.sdkman/candidates/java/current/bin:/opt/homebrew/Cellar/zplug/2.4.2/bin:/Users/victor/.goenv/versions/1.18.1/bin:/Users/victor/.goenv/shims:/Users/victor/.goenv/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki:/Users/victor/go/1.18.1/bin:/opt/homebrew/opt/fzf/bin

	go:	/Users/victor/.goenv/versions/1.18.1/bin/go: go version go1.18.1 darwin/arm64

	gotests:	/Users/victor/go/1.18.1/bin/gotests	(version: v1.6.0 built with go: go1.18.1)
	gomodifytags:	/Users/victor/go/1.18.1/bin/gomodifytags	(version: v1.16.0 built with go: go1.18.1)
	impl:	/Users/victor/go/1.18.1/bin/impl	(version: v1.1.0 built with go: go1.18.1)
	goplay:	/Users/victor/go/1.18.1/bin/goplay	(version: v1.0.0 built with go: go1.18.1)
	staticcheck:	/Users/victor/go/1.18.1/bin/staticcheck	(version: v0.3.2 built with go: go1.18.1)
	gopls:	/Users/victor/go/1.18.1/bin/gopls	(version: v0.8.4 built with go: go1.18.1)

go env
Workspace Folder (rename_repro): /Users/victor/Desktop/rename_repro
	GO111MODULE=""
	GOARCH="arm64"
	GOBIN=""
	GOCACHE="/Users/victor/Library/Caches/go-build"
	GOENV="/Users/victor/Library/Application Support/go/env"
	GOEXE=""
	GOEXPERIMENT=""
	GOFLAGS=""
	GOHOSTARCH="arm64"
	GOHOSTOS="darwin"
	GOINSECURE=""
	GOMODCACHE="/Users/victor/go/1.18.1/pkg/mod"
	GONOPROXY="github.com/launchdarkly"
	GONOSUMDB="github.com/launchdarkly"
	GOOS="darwin"
	GOPATH="/Users/victor/go/1.18.1"
	GOPRIVATE="github.com/launchdarkly"
	GOPROXY="https://proxy.golang.org,direct"
	GOROOT="/Users/victor/.goenv/versions/1.18.1"
	GOSUMDB="sum.golang.org"
	GOTMPDIR=""
	GOTOOLDIR="/Users/victor/.goenv/versions/1.18.1/pkg/tool/darwin_arm64"
	GOVCS=""
	GOVERSION="go1.18.1"
	GCCGO="gccgo"
	AR="ar"
	CC="clang"
	CXX="clang++"
	CGO_ENABLED="1"
	GOMOD="/Users/victor/Desktop/rename_repro/go.mod"
	GOWORK=""
	CGO_CFLAGS="-g -O2"
	CGO_CPPFLAGS=""
	CGO_CXXFLAGS="-g -O2"
	CGO_FFLAGS="-g -O2"
	CGO_LDFLAGS="-g -O2"
	PKG_CONFIG="pkg-config"
	GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/bc/kst12tgd65g659vtwmrw51r00000gn/T/go-build596486156=/tmp/go-build -gno-record-gcc-switches -fno-common"

Share the Go related settings you have added/edited

Run Preferences: Open Settings (JSON) command to open your settings.json file.
Share all the settings with the go. or ["go"] or gopls prefixes.

No go settings touched, this is a fairly clean install of vscode.

Describe the bug

Renaming a method in an interface does not rename implementations of that method. The editor is aware of the implementing methods, and even prevents you from triggering the rename from the implementing method. The editor instructs you to rename the symbol in the interface if you want to change the interface and the implementation. But following those instructions does not rename the implementation.

I expect to be able to rename an interface method and have that change propagate to all implementations. I also expect to be able to rename a method in an implementation and have that propagate to the interface and all other implementations.

I'm not sure if this is a vscode bug or a gopls bug. This flow works correctly in Goland.

Steps to reproduce the behavior:

  1. Create a simple go program with an interface and a type that implements it, e.g. https://gist.github.com/vlymar/46c9da770e4ab5ab2e094e86fba46bc9
  2. Right click on the method signature in the interface (e.g. line 4), click Rename Symbol. Preview the changes and note that the implementation is not updated.
  3. Right click on the method name for the type that implements the interface (e.g. line 9) and click "Rename Symbol." Try renaming and note this error message:
    renaming this method "do" to "dog" would make github.com/vlymar/vscode-rename-bug-report.coolDoer no longer assignable to interface doer (rename github.com/vlymar/vscode-rename-bug-report.doer.do if you intend to change both types)

Note that this exact behavior only happens if you have an explicit assignment of the implementing type to a variable with the interface type (e.g. line 12). If you don't explicitly assign to the interface type:

  • renaming the interface method still does not propagate
  • no error appears when renaming the implementing method (and change does not propagate to interface)
  • however, vscode is still clearly aware of the relationship between the interface and the implementation (right click on the interface method and click "Find all implementations").

Screenshots or recordings

Let me know if my steps above aren't enough and I'll provide a recording.

Thanks for looking into this! Let me know how I can help.

@gopherbot gopherbot added this to the Untriaged milestone Jun 3, 2022
@jamalc jamalc modified the milestones: Untriaged, vscode-go/later Jun 6, 2022
@hyangah hyangah added gopls gopls related issues gopls/refactoring refactoring related issues labels Jun 8, 2022
@nilsanderselde
Copy link

nilsanderselde commented Aug 31, 2022

I encounter this often. The workaround is tedious (manual renaming of implementations). Should be able to rename the interface method and have it rename the implementations.

@FloatingSunfish
Copy link

FloatingSunfish commented Oct 6, 2022

I hope this issue gets fixed soon because renaming interfaces is a basic refactoring action.
Having to manually fix broken implementations after a rename shouldn't be a problem for modern programming languages and tools, especially for languages that strive for elegance like Go.

@andrewbaxter
Copy link

This is bad because if you try to rename the impl method instead, it tells you to rename the interface method (which breaks everything).

This doesn't seem like an exact match, but I think it's relevant? golang/go#34438

@marktiro
Copy link

Yes and yes.
We need that feature because it really helps with refactoring where you need to rename a function everywhere, for example. Of course it is bad from philosophical point of view, but it can be a separate feature for those who really needs it.

It is possible in Goland (jetbrains) and that feature is used a lot there. Let's implement it in vscode too!

@owenhaynes
Copy link

Without any good UX I don't think this is possible. How can gopls be sure you want to change something that looks like you implement the interface you are changing? For example you could be changing String() string to String(format strind) string and now you broken places that was using the GoStringer interface such as fmt.Println

@KrzysztofJopek
Copy link

KrzysztofJopek commented Jul 21, 2023

What about using changeAnnotations with needConfirmation field set to true. It will display a confirmation prompt for every struct which currently implements the interface. User can decide which implementation has to be renamed.

Some time ago, I did hacky PoC of such feature:
one-file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gopls/refactoring refactoring related issues gopls gopls related issues
Projects
None yet
Development

No branches or pull requests

10 participants