Skip to content

Commit 1bd98f4

Browse files
committed
x/tools/gopls: implement struct field generation quickfix
1 parent c62da73 commit 1bd98f4

File tree

10 files changed

+177
-359
lines changed

10 files changed

+177
-359
lines changed

gopls/doc/release/v0.17.0.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ where T is the concrete type and f is the undefined method.
8888
The stub method's signature is inferred
8989
from the context of the call.
9090

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

10193
The new `yield` analyzer detects mistakes using the `yield` function
@@ -122,3 +114,11 @@ Since this feature is implemented by the server (gopls), it is compatible with
122114
all LSP-compliant editors. VS Code users may continue to use the client-side
123115
`Go: Generate Unit Tests For file/function/package` command which utilizes the
124116
[gotests](https://github.com/cweill/gotests) tool.
117+
118+
## Generate missing struct field from access
119+
When you attempt to access a field on a type that does not have the field,
120+
the compiler will report an error like “type X has no field or method Y”.
121+
Gopls now offers a new code action, “Declare missing field of T.f”,
122+
where T is the concrete type and f is the undefined field.
123+
The stub field's signature is inferred
124+
from the context of the access.

gopls/internal/analysis/yield/testdata/src/a/a.go

-3
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ func tricky(in io.ReadCloser) func(yield func(string, error) bool) {
8383
}
8484
}
8585
}
86-
<<<<<<< HEAD
8786

8887
// Regression test for issue #70598.
8988
func shortCircuitAND(yield func(int) bool) {
@@ -119,5 +118,3 @@ func tricky3(yield func(int) bool) {
119118
yield(3)
120119
}
121120
}
122-
=======
123-
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)

gopls/internal/analysis/yield/yield.go

-12
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ import (
2020
_ "embed"
2121
"fmt"
2222
"go/ast"
23-
<<<<<<< HEAD
2423
"go/constant"
25-
=======
26-
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
2724
"go/token"
2825
"go/types"
2926

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

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

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

179170
return nil, nil
180171
}
181-
<<<<<<< HEAD
182172

183173
func unnegate(cond ssa.Value, t, f *ssa.BasicBlock) (_ ssa.Value, _, _ *ssa.BasicBlock) {
184174
if unop, ok := cond.(*ssa.UnOp); ok && unop.Op == token.NOT {
185175
return unop.X, f, t
186176
}
187177
return cond, t, f
188178
}
189-
=======
190-
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)

gopls/internal/analysis/yield/yield_test.go

-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ func Test(t *testing.T) {
1515
testdata := analysistest.TestData()
1616
analysistest.Run(t, testdata, yield.Analyzer, "a")
1717
}
18-
e

gopls/internal/doc/api.json

-3
Original file line numberDiff line numberDiff line change
@@ -1304,15 +1304,12 @@
13041304
"Default": false
13051305
},
13061306
{
1307-
<<<<<<< HEAD
13081307
"Name": "waitgroup",
13091308
"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()",
13101309
"URL": "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup",
13111310
"Default": true
13121311
},
13131312
{
1314-
=======
1315-
>>>>>>> 9b6e4f21d (gopls/internal/analysis/yield: analyzer for iterator (yield) mistakes)
13161313
"Name": "yield",
13171314
"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.",
13181315
"URL": "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/yield",

gopls/internal/golang/assembly.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ew// Copyright 2024 The Go Authors. All rights reserved.
1+
// Copyright 2024 The Go Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

gopls/internal/golang/codeaction.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ func (si *StructFieldInfo) Emit(out *bytes.Buffer, qual types.Qualifier) error {
408408
}
409409

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

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

0 commit comments

Comments
 (0)