diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md index 80ee65d73b2..c3e19aca8d9 100644 --- a/gopls/doc/analyzers.md +++ b/gopls/doc/analyzers.md @@ -573,6 +573,25 @@ This functionality is similar to https://github.com/sqs/goreturns. **Enabled by default.** +## **implementmissing** + +suggested fixes for "undeclared name: %s" on a function call + +This checker provides suggested fixes for type errors of the +type "undeclared name: %s" that happen for a function call. For example: + func m() { + a(1) + } +will turn into + func m() { + a(1) + } + + func a(i int) {} + + +**Disabled by default. Enable it by setting `"analyses": {"implementmissing": true}`.** + ## **nonewvars** suggested fixes for "no new vars on left side of :=" diff --git a/internal/lsp/analysis/implementmissing/missingfunc.go b/internal/lsp/analysis/implementmissing/missingfunc.go new file mode 100644 index 00000000000..2e4bc3c324f --- /dev/null +++ b/internal/lsp/analysis/implementmissing/missingfunc.go @@ -0,0 +1,274 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package implementmissing defines an Analyzer that will attempt to +// automatically implement a function that is currently undeclared. +package implementmissing + +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/types" + "strings" + "unicode" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/internal/analysisinternal" +) + +const Doc = `suggested fixes for "undeclared name: %s" on a function call + +This checker provides suggested fixes for type errors of the +type "undeclared name: %s" that happen for a function call. For example: + func m() { + a(1) + } +will turn into + func m() { + a(1) + } + + func a(i int) {} +` + +var Analyzer = &analysis.Analyzer{ + Name: "implementmissing", + Doc: Doc, + Requires: []*analysis.Analyzer{}, + Run: run, + RunDespiteErrors: true, +} + +const undeclaredNamePrefix = "undeclared name: " + +func run(pass *analysis.Pass) (interface{}, error) { + info := pass.TypesInfo + if info == nil { + return nil, fmt.Errorf("nil TypeInfo") + } + + errors := analysisinternal.GetTypeErrors(pass) + for _, typeErr := range errors { + // Filter out the errors that are not relevant to this analyzer. + if !FixesError(typeErr.Msg) { + continue + } + + var file *ast.File + for _, f := range pass.Files { + if f.Pos() <= typeErr.Pos && typeErr.Pos <= f.End() { + file = f + break + } + } + if file == nil { + continue + } + + var buf bytes.Buffer + if err := format.Node(&buf, pass.Fset, file); err != nil { + continue + } + typeErrEndPos := analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), typeErr.Pos) + + // Get the path for the relevant range. + path, _ := astutil.PathEnclosingInterval(file, typeErr.Pos, typeErrEndPos) + if len(path) < 2 { + return nil, nil + } + + // Check to make sure we're dealing with a function call, we don't want to + // deal with undeclared variables here. + call, ok := path[1].(*ast.CallExpr) + if !ok { + return nil, nil + } + + ident, ok := path[0].(*ast.Ident) + if !ok { + return nil, nil + } + + var paramNames []string + var paramTypes []types.Type + + // keep track of all param names to later ensure uniqueness + namesCount := map[string]int{} + + for _, arg := range call.Args { + ty := pass.TypesInfo.TypeOf(arg) + if ty == nil { + return nil, nil + } + + switch t := ty.(type) { + // this is the case where another function call returning multiple + // results is used as an argument + case *types.Tuple: + n := t.Len() + for i := 0; i < n; i++ { + name := typeToArgName(t.At(i).Type()) + namesCount[name]++ + + paramNames = append(paramNames, name) + paramTypes = append(paramTypes, types.Default(t.At(i).Type())) + } + + default: + // does the argument have a name we can reuse? + // only happens in case of a *ast.Ident + var name string + if ident, ok := arg.(*ast.Ident); ok { + name = ident.Name + } + + if name == "" { + name = typeToArgName(ty) + } + + namesCount[name]++ + + paramNames = append(paramNames, name) + paramTypes = append(paramTypes, types.Default(ty)) + } + } + + for n, c := range namesCount { + // Any names we saw more than once will need a unique suffix added + // on. Reset the count to 1 to act as the suffix for the first + // occurrence of that name. + if c >= 2 { + namesCount[n] = 1 + } else { + delete(namesCount, n) + } + } + + params := &ast.FieldList{ + List: []*ast.Field{}, + } + + for i, name := range paramNames { + if suffix, repeats := namesCount[name]; repeats { + namesCount[name]++ + name = fmt.Sprintf("%s%d", name, suffix) + } + + // only worth checking after previous param in the list + if i > 0 { + // if type of parameter at hand is the same as the previous one, + // add it to the previous param list of identifiers so to have: + // (s1, s2 string) + // and not + // (s1 string, s2 string) + if paramTypes[i] == paramTypes[i-1] { + params.List[len(params.List)-1].Names = append(params.List[len(params.List)-1].Names, ast.NewIdent(name)) + continue + } + } + + params.List = append(params.List, &ast.Field{ + Names: []*ast.Ident{ + ast.NewIdent(name), + }, + Type: analysisinternal.TypeExpr(pass.Fset, file, pass.Pkg, paramTypes[i]), + }) + } + + eof := file.End() + + decl := &ast.FuncDecl{ + Name: &ast.Ident{ + Name: ident.Name, + }, + Type: &ast.FuncType{ + Func: file.End(), + Params: params, + Results: &ast.FieldList{}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + X: &ast.CallExpr{ + Fun: &ast.Ident{ + Name: "panic", + }, + Args: []ast.Expr{ + &ast.BasicLit{ + Value: `"not implemented"`, + }, + }, + }, + }, + }, + }, + } + + var declBuf bytes.Buffer + if err := format.Node(&declBuf, pass.Fset, decl); err != nil { + return nil, err + } + + text := append([]byte("\n\n"), declBuf.Bytes()...) + text = append(text, []byte("\n")...) + + pass.Report(analysis.Diagnostic{ + Pos: typeErr.Pos, + End: typeErr.Pos, + Message: typeErr.Msg, + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Implement function " + ident.Name, + TextEdits: []analysis.TextEdit{{ + Pos: eof, + End: eof, + NewText: text, + }}, + }, + }, + Related: []analysis.RelatedInformation{}, + }) + } + return nil, nil +} + +func FixesError(msg string) bool { + return strings.HasPrefix(msg, undeclaredNamePrefix) +} + +func typeToArgName(ty types.Type) string { + s := types.Default(ty).String() + + switch t := ty.(type) { + case *types.Basic: + // use first letter in type name for basic types + return s[0:1] + case *types.Slice: + // use element type to decide var name for slices + return typeToArgName(t.Elem()) + case *types.Array: + // use element type to decide var name for arrays + return typeToArgName(t.Elem()) + case *types.Chan: + return "ch" + } + + s = strings.TrimFunc(s, func(r rune) bool { + return !unicode.IsLetter(r) + }) + + if s == "error" { + return "err" + } + + // remove package (if present) + // and make first letter lowercase + parts := strings.Split(s, ".") + a := []rune(parts[len(parts)-1]) + a[0] = unicode.ToLower(a[0]) + return string(a) +} diff --git a/internal/lsp/analysis/implementmissing/missingfunc_test.go b/internal/lsp/analysis/implementmissing/missingfunc_test.go new file mode 100644 index 00000000000..7c9b5736562 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/missingfunc_test.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package implementmissing_test + +import ( + "testing" + + "golang.org/x/tools/go/analysis/analysistest" + "golang.org/x/tools/internal/lsp/analysis/implementmissing" +) + +func Test(t *testing.T) { + testdata := analysistest.TestData() + analysistest.RunWithSuggestedFixes(t, testdata, implementmissing.Analyzer, "missingfunction") +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go new file mode 100644 index 00000000000..fa9151843de --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func channels(s string) { + undefinedChannels(c()) // want "undeclared name: undefinedChannels" +} + +func c() (<-chan string, chan string) { + return make(<-chan string), make(chan string) +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go.golden new file mode 100644 index 00000000000..c8578e68ea3 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/channels.go.golden @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func channels(s string) { + undefinedChannels(c()) // want "undeclared name: undefinedChannels" +} + +func c() (<-chan string, chan string) { + return make(<-chan string), make(chan string) +} + +func undefinedChannels(ch1 <-chan string, ch2 chan string) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go new file mode 100644 index 00000000000..4a6ec62368f --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go @@ -0,0 +1,10 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func consecutiveParams() { + var s string + undefinedConsecutiveParams(s, s) // want "undeclared name: undefinedConsecutiveParams" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go.golden new file mode 100644 index 00000000000..050b0fcf922 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/consecutive_params.go.golden @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func consecutiveParams() { + var s string + undefinedConsecutiveParams(s, s) // want "undeclared name: undefinedConsecutiveParams" +} + +func undefinedConsecutiveParams(s1, s2 string) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go new file mode 100644 index 00000000000..49c5258ff9a --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go @@ -0,0 +1,10 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func errorParam() { + var err error + undefinedErrorParam(err) // want "undeclared name: undefinedErrorParam" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go.golden new file mode 100644 index 00000000000..1661fc4cc3f --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/error_param.go.golden @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func errorParam() { + var err error + undefinedErrorParam(err) // want "undeclared name: undefinedErrorParam" +} + +func undefinedErrorParam(err error) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go new file mode 100644 index 00000000000..46c045c3d4a --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +type T struct{} + +func literals() { + undefinedLiterals("hey compiler", T{}, &T{}) // want "undeclared name: undefinedLiterals" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go.golden new file mode 100644 index 00000000000..ee32b710cb4 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/literals.go.golden @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +type T struct{} + +func literals() { + undefinedLiterals("hey compiler", T{}, &T{}) // want "undeclared name: undefinedLiterals" +} + +func undefinedLiterals(s string, t1 T, t2 *T) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go new file mode 100644 index 00000000000..b8330ec2c11 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +import "time" + +func operation() { + undefinedOperation(10 * time.Second) // want "undeclared name: undefinedOperation" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go.golden new file mode 100644 index 00000000000..1bf35cf61c7 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/operation.go.golden @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +import "time" + +func operation() { + undefinedOperation(10 * time.Second) // want "undeclared name: undefinedOperation" +} + +func undefinedOperation(duration time.Duration) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go new file mode 100644 index 00000000000..5db716f7f65 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go @@ -0,0 +1,10 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func selector() { + m := map[int]bool{} + undefinedSelector(m[1]) // want "undeclared name: undefinedSelector" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go.golden new file mode 100644 index 00000000000..9d66f6abddb --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/selector.go.golden @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func selector() { + m := map[int]bool{} + undefinedSelector(m[1]) // want "undeclared name: undefinedSelector" +} + +func undefinedSelector(b bool) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go new file mode 100644 index 00000000000..179954cdecf --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func slice() { + undefinedSlice([]int{1, 2}) // want "undeclared name: undefinedSlice" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go.golden new file mode 100644 index 00000000000..75f457878a3 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/slice.go.golden @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func slice() { + undefinedSlice([]int{1, 2}) // want "undeclared name: undefinedSlice" +} + +func undefinedSlice(i []int) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go new file mode 100644 index 00000000000..673f60775ef --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func tuple() { + undefinedTuple(b()) // want "undeclared name: undefinedTuple" +} + +func b() (string, error) { + return "", nil +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go.golden new file mode 100644 index 00000000000..ac33ed04a71 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/tuple.go.golden @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func tuple() { + undefinedTuple(b()) // want "undeclared name: undefinedTuple" +} + +func b() (string, error) { + return "", nil +} + +func undefinedTuple(s string, err error) { panic("not implemented") } diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go new file mode 100644 index 00000000000..2f18498d2a3 --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func uniqueArguments() { + var s string + var i int + undefinedUniqueArguments(s, i, s) // want "undeclared name: undefinedUniqueArguments" +} diff --git a/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go.golden b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go.golden new file mode 100644 index 00000000000..28c27d87d0a --- /dev/null +++ b/internal/lsp/analysis/implementmissing/testdata/src/missingfunction/unique_params.go.golden @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package missingfunction + +func uniqueArguments() { + var s string + var i int + undefinedUniqueArguments(s, i, s) // want "undeclared name: undefinedUniqueArguments" +} + +func undefinedUniqueArguments(s1 string, i int, s2 string) { panic("not implemented") } diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go index 9b5734fa87a..4b67341363a 100755 --- a/internal/lsp/source/api_json.go +++ b/internal/lsp/source/api_json.go @@ -556,6 +556,11 @@ var GeneratedAPIJSON = &APIJSON{ Doc: "suggested fixes for \"wrong number of return values (want %d, got %d)\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"wrong number of return values (want %d, got %d)\". For example:\n\tfunc m() (int, string, *bool, error) {\n\t\treturn\n\t}\nwill turn into\n\tfunc m() (int, string, *bool, error) {\n\t\treturn 0, \"\", nil, nil\n\t}\n\nThis functionality is similar to https://github.com/sqs/goreturns.\n", Default: "true", }, + { + Name: "\"implementmissing\"", + Doc: "suggested fixes for \"undeclared name: %s\" on a function call\n\nThis checker provides suggested fixes for type errors of the\ntype \"undeclared name: %s\" that happen for a function call. For example:\n\tfunc m() {\n\t a(1)\n\t}\nwill turn into\n\tfunc m() {\n\t a(1)\n\t}\n\n\tfunc a(i int) {}\n", + Default: "false", + }, { Name: "\"nonewvars\"", Doc: "suggested fixes for \"no new vars on left side of :=\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"no new vars on left side of :=\". For example:\n\tz := 1\n\tz := 2\nwill turn into\n\tz := 1\n\tz = 2\n", @@ -1124,6 +1129,11 @@ var GeneratedAPIJSON = &APIJSON{ Doc: "suggested fixes for \"wrong number of return values (want %d, got %d)\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"wrong number of return values (want %d, got %d)\". For example:\n\tfunc m() (int, string, *bool, error) {\n\t\treturn\n\t}\nwill turn into\n\tfunc m() (int, string, *bool, error) {\n\t\treturn 0, \"\", nil, nil\n\t}\n\nThis functionality is similar to https://github.com/sqs/goreturns.\n", Default: true, }, + { + Name: "implementmissing", + Doc: "suggested fixes for \"undeclared name: %s\" on a function call\n\nThis checker provides suggested fixes for type errors of the\ntype \"undeclared name: %s\" that happen for a function call. For example:\n\tfunc m() {\n\t a(1)\n\t}\nwill turn into\n\tfunc m() {\n\t a(1)\n\t}\n\n\tfunc a(i int) {}\n", + Default: false, + }, { Name: "nonewvars", Doc: "suggested fixes for \"no new vars on left side of :=\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"no new vars on left side of :=\". For example:\n\tz := 1\n\tz := 2\nwill turn into\n\tz := 1\n\tz = 2\n", diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go index 9bc73a9d7c7..19c99110417 100644 --- a/internal/lsp/source/options.go +++ b/internal/lsp/source/options.go @@ -49,6 +49,7 @@ import ( "golang.org/x/tools/go/analysis/passes/unusedwrite" "golang.org/x/tools/internal/lsp/analysis/fillreturns" "golang.org/x/tools/internal/lsp/analysis/fillstruct" + "golang.org/x/tools/internal/lsp/analysis/implementmissing" "golang.org/x/tools/internal/lsp/analysis/nonewvars" "golang.org/x/tools/internal/lsp/analysis/noresultvalues" "golang.org/x/tools/internal/lsp/analysis/simplifycompositelit" @@ -754,6 +755,9 @@ func (o *Options) enableAllExperimentMaps() { if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok { o.Analyses[unusedparams.Analyzer.Name] = true } + if _, ok := o.Analyses[implementmissing.Analyzer.Name]; !ok { + o.Analyses[implementmissing.Analyzer.Name] = true + } } func (o *Options) set(name string, value interface{}, seen map[string]struct{}) OptionResult { @@ -1171,6 +1175,11 @@ func typeErrorAnalyzers() map[string]*Analyzer { ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, Enabled: true, }, + implementmissing.Analyzer.Name: { + Analyzer: implementmissing.Analyzer, + ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, + Enabled: false, + }, nonewvars.Analyzer.Name: { Analyzer: nonewvars.Analyzer, Enabled: true,