Skip to content

Commit

Permalink
x/tools/gopls: implement struct field generation quickfix
Browse files Browse the repository at this point in the history
  • Loading branch information
dennypenta committed Dec 3, 2024
1 parent c62da73 commit 1bd98f4
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 359 deletions.
16 changes: 8 additions & 8 deletions gopls/doc/release/v0.17.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,6 @@ where T is the concrete type and f is the undefined method.
The stub method's signature is inferred
from the context of the call.

## Generate missing struct field from access
When you attempt to access a field on a type that does not have the field,
the compiler will report an error like “type X has no field or method Y”.
Gopls now offers a new code action, “Declare missing field of T.f”,
where T is the concrete type and f is the undefined field.
The stub field's signature is inferred
from the context of the access.

## `yield` analyzer

The new `yield` analyzer detects mistakes using the `yield` function
Expand All @@ -122,3 +114,11 @@ Since this feature is implemented by the server (gopls), it is compatible with
all LSP-compliant editors. VS Code users may continue to use the client-side
`Go: Generate Unit Tests For file/function/package` command which utilizes the
[gotests](https://github.com/cweill/gotests) tool.

## Generate missing struct field from access
When you attempt to access a field on a type that does not have the field,
the compiler will report an error like “type X has no field or method Y”.
Gopls now offers a new code action, “Declare missing field of T.f”,
where T is the concrete type and f is the undefined field.
The stub field's signature is inferred
from the context of the access.
3 changes: 0 additions & 3 deletions gopls/internal/analysis/yield/testdata/src/a/a.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ func tricky(in io.ReadCloser) func(yield func(string, error) bool) {
}
}
}
<<<<<<< HEAD

// Regression test for issue #70598.
func shortCircuitAND(yield func(int) bool) {
Expand Down Expand Up @@ -119,5 +118,3 @@ func tricky3(yield func(int) bool) {
yield(3)
}
}
=======
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
12 changes: 0 additions & 12 deletions gopls/internal/analysis/yield/yield.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ import (
_ "embed"
"fmt"
"go/ast"
<<<<<<< HEAD
"go/constant"
=======
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
"go/token"
"go/types"

Expand Down Expand Up @@ -123,7 +120,6 @@ func run(pass *analysis.Pass) (interface{}, error) {
// In that case visit only the "if !yield()" block.
cond := instr.Cond
t, f := b.Succs[0], b.Succs[1]
<<<<<<< HEAD

// Strip off any NOT operator.
cond, t, f = unnegate(cond, t, f)
Expand Down Expand Up @@ -152,11 +148,6 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
}

=======
if unop, ok := cond.(*ssa.UnOp); ok && unop.Op == token.NOT {
cond, t, f = unop.X, f, t
}
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
if cond, ok := cond.(*ssa.Call); ok && ssaYieldCalls[cond] != nil {
// Skip the successor reached by "if yield() { ... }".
} else {
Expand All @@ -178,13 +169,10 @@ func run(pass *analysis.Pass) (interface{}, error) {

return nil, nil
}
<<<<<<< HEAD

func unnegate(cond ssa.Value, t, f *ssa.BasicBlock) (_ ssa.Value, _, _ *ssa.BasicBlock) {
if unop, ok := cond.(*ssa.UnOp); ok && unop.Op == token.NOT {
return unop.X, f, t
}
return cond, t, f
}
=======
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
1 change: 0 additions & 1 deletion gopls/internal/analysis/yield/yield_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ func Test(t *testing.T) {
testdata := analysistest.TestData()
analysistest.Run(t, testdata, yield.Analyzer, "a")
}
e
3 changes: 0 additions & 3 deletions gopls/internal/doc/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -1304,15 +1304,12 @@
"Default": false
},
{
<<<<<<< HEAD
"Name": "waitgroup",
"Doc": "check for misuses of sync.WaitGroup\n\nThis analyzer detects mistaken calls to the (*sync.WaitGroup).Add\nmethod from inside a new goroutine, causing Add to race with Wait:\n\n\t// WRONG\n\tvar wg sync.WaitGroup\n\tgo func() {\n\t wg.Add(1) // \"WaitGroup.Add called from inside new goroutine\"\n\t defer wg.Done()\n\t ...\n\t}()\n\twg.Wait() // (may return prematurely before new goroutine starts)\n\nThe correct code calls Add before starting the goroutine:\n\n\t// RIGHT\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\t...\n\t}()\n\twg.Wait()",
"URL": "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup",
"Default": true
},
{
=======
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
"Name": "yield",
"Doc": "report calls to yield where the result is ignored\n\nAfter a yield function returns false, the caller should not call\nthe yield function again; generally the iterator should return\npromptly.\n\nThis example fails to check the result of the call to yield,\ncausing this analyzer to report a diagnostic:\n\n\tyield(1) // yield may be called again (on L2) after returning false\n\tyield(2)\n\nThe corrected code is either this:\n\n\tif yield(1) { yield(2) }\n\nor simply:\n\n\t_ = yield(1) \u0026\u0026 yield(2)\n\nIt is not always a mistake to ignore the result of yield.\nFor example, this is a valid single-element iterator:\n\n\tyield(1) // ok to ignore result\n\treturn\n\nIt is only a mistake when the yield call that returned false may be\nfollowed by another call.",
"URL": "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/yield",
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/golang/assembly.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ew// Copyright 2024 The Go Authors. All rights reserved.
// Copyright 2024 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.

Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/golang/codeaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ func (si *StructFieldInfo) Emit(out *bytes.Buffer, qual types.Qualifier) error {
}

// Get types from context at the selector expression position
typesFromContext := stubmethods.TypesFromContext(si.Info, si.Path, si.Expr.Pos())
typesFromContext := typesutil.TypesFromContext(si.Info, si.Path, si.Expr.Pos())

// Default to interface{} if we couldn't determine the type from context
var fieldType types.Type
Expand Down
Loading

0 comments on commit 1bd98f4

Please sign in to comment.