Skip to content

Commit

Permalink
gopls/internal/lsp/source/completion: complete return snippet
Browse files Browse the repository at this point in the history
Offer a snippet completing a return statement with return values.
Each return value is wrapped in a snippet placeholder, with the
corresponding zero value as default.

The snippet is only offered inside functions that have return parameters.
It is ranked below a plain return keyword.

Closes golang/go#64266

Change-Id: Ifd7cd83f57e8d60ed5c45c2ff049378670473b7d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/546775
Auto-Submit: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
vikblom authored and gopherbot committed Jan 2, 2024
1 parent a08f286 commit d47b14c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
59 changes: 59 additions & 0 deletions gopls/internal/lsp/source/completion/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"go/ast"
"go/token"
"go/types"
"strings"

"golang.org/x/tools/gopls/internal/lsp/cache"
"golang.org/x/tools/gopls/internal/lsp/protocol"
Expand All @@ -21,6 +22,7 @@ import (
func (c *completer) addStatementCandidates() {
c.addErrCheck()
c.addAssignAppend()
c.addReturnZeroValues()
}

// addAssignAppend offers a completion candidate of the form:
Expand Down Expand Up @@ -359,3 +361,60 @@ func getTestVar(enclosingFunc *funcInfo, pkg *cache.Package) string {

return ""
}

// addReturnZeroValues offers a snippet candidate on the form:
//
// return 0, "", nil
//
// Requires a partially or fully written return keyword at position.
// Requires current position to be in a function with more than
// zero return parameters.
func (c *completer) addReturnZeroValues() {
if len(c.path) < 2 || c.enclosingFunc == nil || !c.opts.placeholders {
return
}
result := c.enclosingFunc.sig.Results()
if result.Len() == 0 {
return
}

// Offer just less than we expect from return as a keyword.
var score = stdScore - 0.01
switch c.path[0].(type) {
case *ast.ReturnStmt, *ast.Ident:
f := c.matcher.Score("return")
if f <= 0 {
return
}
score *= float64(f)
default:
return
}

// The snippet will have a placeholder over each return value.
// The label will not.
var snip snippet.Builder
var label strings.Builder
snip.WriteText("return ")
fmt.Fprintf(&label, "return ")

for i := 0; i < result.Len(); i++ {
if i > 0 {
snip.WriteText(", ")
fmt.Fprintf(&label, ", ")
}

zero := formatZeroValue(result.At(i).Type(), c.qf)
snip.WritePlaceholder(func(b *snippet.Builder) {
b.WriteText(zero)
})
fmt.Fprintf(&label, zero)
}

c.items = append(c.items, CompletionItem{
Label: label.String(),
Kind: protocol.SnippetCompletion,
Score: score,
snippet: &snip,
})
}
13 changes: 13 additions & 0 deletions gopls/internal/test/marker/testdata/completion/statements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,16 @@ func BenchmarkErr(b *testing.B) {
_, err := os.Open("foo")
//@snippet("", stmtOneIfErrBFatal, "if err != nil {\n\tb.Fatal(err)\n\\}")
}

-- return.go --
package statements

//@item(stmtReturnZeroValues, `return 0, "", nil`)

func foo() (int, string, error) {
ret //@snippet(" ", stmtReturnZeroValues, "return ${1:0}, ${2:\"\"}, ${3:nil}")
}

func bar() (int, string, error) {
return //@snippet(" ", stmtReturnZeroValues, "return ${1:0}, ${2:\"\"}, ${3:nil}")
}

0 comments on commit d47b14c

Please sign in to comment.