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: Feature Request: Support for "Inline Method" refactoring code action #59243

Closed
walles opened this issue Mar 25, 2023 · 3 comments
Assignees
Labels
FeatureRequest gopls Issues related to the Go language server, gopls. Refactoring Issues related to refactoring tools Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@walles
Copy link

walles commented Mar 25, 2023

About once a week I look for the Inline Method refactoring in VSCode.

If this could be added that would be super!

gopls version

Build info
----------
golang.org/x/tools/gopls v0.11.0
    golang.org/x/tools/gopls@v0.11.0 h1:/nvKHdTtePQmrv9XN3gIUN9MOdUrKzO/dcqgbG6x8EY=
    github.com/BurntSushi/toml@v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
    github.com/google/go-cmp@v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
    github.com/sergi/go-diff@v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
    golang.org/x/exp@v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
    golang.org/x/exp/typeparams@v0.0.0-20221031165847-c99f073a8326 h1:fl8k2zg28yA23264d82M4dp+YlJ3ngDcpuB1bewkQi4=
    golang.org/x/mod@v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
    golang.org/x/sync@v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
    golang.org/x/sys@v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
    golang.org/x/text@v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
    golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8 h1:7/HkGkN/2ktghBCSRRgp31wAww4syfsW52tj7yirjWk=
    golang.org/x/vuln@v0.0.0-20221109205719-3af8368ee4fe h1:qptQiQwEpETwDiz85LKtChqif9xhVkAm8Nhxs0xnTww=
    honnef.co/go/tools@v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
    mvdan.cc/gofumpt@v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
    mvdan.cc/xurls/v2@v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
go: go1.20.1

go env

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/johan/Library/Caches/go-build"
GOENV="/Users/johan/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/johan/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/johan/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.20.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.20.2/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/cg/d7qzk4s13s9c8t49t3txdjpr0000gn/T/go-build213492774=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Put the cursor on either of the PrintHellos.

package main

import "fmt"

func PrintHello() {
	fmt.Println("Hello, 世界")
}

func main() {
	PrintHello()
}

What did you expect to see?

A 💡 with a Code Action to "Inline PrintHello".

The result should be this:

package main

import "fmt"

func main() {
	fmt.Println("Hello, 世界")
}

What did you see instead?

No obvious way of having gopls inline PrintHello() for me.

Editor and settings

{
  "files.exclude": {
    "node_modules/": true,
    "**/*.pyc": true
  },
  "editor.minimap.enabled": false,
  "python.linting.mypyEnabled": true,
  "git.autofetch": true,
  "files.associations": {
    "*.1": "troff",
    "COMMIT_EDITMSG": "git-commit",
    "TAG_EDITMSG": "git-commit"
  },
  "git.confirmSync": false,
  "python.linting.flake8Args": [
    "--ignore=E501,W504"
  ],
  "workbench.startupEditor": "newUntitledFile",
  "zentabs.maximumOpenedTabs": 4,
  "files.trimTrailingWhitespace": true,
  "editor.scrollBeyondLastLine": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.dart": true,
    "source.fixAll.eslint": true
  },
  "go.useLanguageServer": true,
  "editor.cursorSurroundingLines": 4,
  "[javascript]": {
    "editor.defaultFormatter": "numso.prettier-standard-vscode"
  },
  "workbench.editor.limit.enabled": true,
  "workbench.editor.limit.value": 5,
  "python.showStartPage": false,
  "[c]": {
    "editor.defaultFormatter": "xaver.clang-format"
  },
  "[cpp]": {
    "editor.defaultFormatter": "xaver.clang-format"
  },
  "rust-analyzer.checkOnSave.command": "clippy",
  "rst.preview.pythonPath": "python3",
  "git.countBadge": "off",
  "scm.countBadge": "off",
  "[html]": {
    "editor.defaultFormatter": "vscode.html-language-features"
  },
  "liveServer.settings.donotShowInfoMsg": true,
  "html.autoClosingTags": false,
  "html.format.endWithNewline": true,
  "workbench.editorAssociations": {
    "*.ipynb": "jupyter-notebook"
  },
  "go.toolsManagement.autoUpdate": true,
  "workbench.editor.untitled.hint": "hidden",
  "explorer.confirmDelete": false,
  "security.workspace.trust.untrustedFiles": "open",
  "notebook.cellToolbarLocation": {
    "default": "right",
    "jupyter-notebook": "left"
  },
  "blender.executables": [
    {
      "path": "/Applications/Blender.app/Contents/MacOS/blender",
      "name": "",
      "isDebug": false
    }
  ],
  "blender.allowModifyExternalPython": true,
  "python.linting.mypyArgs": [
    "--ignore-missing-imports",
    "--follow-imports=silent",
    "--show-column-numbers",
    "--check-untyped-defs"
  ],
  "[dockerfile]": {
    "editor.defaultFormatter": "ms-azuretools.vscode-docker"
  },
  "testExplorer.useNativeTesting": true,
  "python.formatting.provider": "black",
  "terminal.integrated.scrollback": 10000,
  "redhat.telemetry.enabled": true,
  "outline.showArrays": false,
  "outline.showBooleans": false,
  "outline.showConstants": false,
  "outline.showEnumMembers": false,
  "outline.showEnums": false,
  "outline.showFields": false,
  "outline.showKeys": false,
  "outline.showNull": false,
  "outline.showNumbers": false,
  "outline.showObjects": false,
  "outline.showOperators": false,
  "outline.showProperties": false,
  "outline.showStrings": false,
  "outline.showTypeParameters": false,
  "outline.showVariables": false,
  "outline.showStructs": false,
  "breadcrumbs.symbolSortOrder": "name",
  "editor.guides.bracketPairsHorizontal": false,
  "editor.guides.indentation": false,
  "editor.guides.bracketPairs": "active",
  "search.smartCase": true,
  "[dart]": {
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    "editor.rulers": [
      80
    ],
    "editor.selectionHighlight": false,
    "editor.suggest.snippetsPreventQuickSuggestions": false,
    "editor.suggestSelection": "first",
    "editor.tabCompletion": "onlySnippets",
    "editor.wordBasedSuggestions": false
  },
  "editor.fontLigatures": true,
  "editor.fontFamily": "Fira Code, Menlo, Monaco, 'Courier New', monospace",
  "dart.debugExternalPackageLibraries": true,
  "dart.debugSdkLibraries": true,
  "[json]": {
    "editor.defaultFormatter": "vscode.json-language-features"
  },
  "go.lintTool": "golangci-lint",
  "editor.stickyScroll.enabled": true,
  "lldb.suppressUpdateNotifications": true,
  "outline.collapseItems": "alwaysCollapse",
  "python.linting.cwd": "",
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "vscode.json-language-features"
  },
  "javascript.format.enable": false,
  "typescript.format.enable": false,
  "[json-tmLanguage]": {
    "editor.defaultFormatter": "RedCMD.tmlanguage-syntax-highlighter"
  },
  "[python]": {
    "editor.formatOnType": true
  },
  "[markdown]": {
    "editor.defaultFormatter": "numso.prettier-standard-vscode"
  },
  "diffEditor.renderSideBySide": false,
  "git.verboseCommit": true,
  "workbench.sideBar.location": "right"
}
@gopherbot gopherbot added Tools This label describes issues relating to any tools in the x/tools repository. gopls Issues related to the Go language server, gopls. labels Mar 25, 2023
@gopherbot gopherbot added this to the Unreleased milestone Mar 25, 2023
@findleyr findleyr added FeatureRequest Refactoring Issues related to refactoring tools labels Mar 28, 2023
@findleyr
Copy link
Contributor

Thanks for this request. I'm surprised it has not been requested before, but I did not find any dupes.

Right now we're working on a major performance overhaul, but improved refactoring is one of our most requested features.

@findleyr findleyr modified the milestones: Unreleased, gopls/unplanned Mar 28, 2023
@adonovan
Copy link
Member

adonovan commented Apr 7, 2023

A few considerations for the design of this feature. Let f be the candidate function.

  • Is f just { return expr }? If so then it can be inlined into any context. But if it has multiple statements then it can only be inlined into a statement-like context (e.g. y := f()), or an intervening anonymous function is required: g(f(0)) -> g(func(x int) {...}(0)).
  • Does f use defer? Inlining may change its dynamic behavior. recover is another special case.
  • Does f refer to imports or package-level declarations that are not accessible to the caller because it is in a different file, or a different package, or because of shadowing? Alpha-renaming, import insertion, accessibility checking (for unexported symbols or internal packages), and conflict detection are all required in the general case.

These concerns aside, I think it would require very little effort to start with something imperfect and iterate from there.

Another interesting problem is automatically simplifying the inlined body based on knowledge of the arguments. e.g. a range over a slice or map that it known to be nil can be deleted. Simplification of a block of statements might be a useful feature in its own right, independent of inlining.

@adonovan adonovan self-assigned this Aug 28, 2023
@gopherbot
Copy link

Change https://go.dev/cl/523696 mentions this issue: gopls/internal/lsp/source: implement refactor.inline code action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FeatureRequest gopls Issues related to the Go language server, gopls. Refactoring Issues related to refactoring tools Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

4 participants