Skip to content

Commit 13999c2

Browse files
committed
Move GetFieldStubInfo to stubmethods package
1 parent 1675eb9 commit 13999c2

File tree

4 files changed

+80
-81
lines changed

4 files changed

+80
-81
lines changed

gopls/internal/golang/codeaction.go

+1-72
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package golang
66

77
import (
8-
"bytes"
98
"context"
109
"encoding/json"
1110
"fmt"
@@ -42,7 +41,6 @@ import (
4241
//
4342
// See ../protocol/codeactionkind.go for some code action theory.
4443
func CodeActions(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range, diagnostics []protocol.Diagnostic, enabled func(protocol.CodeActionKind) bool, trigger protocol.CodeActionTriggerKind) (actions []protocol.CodeAction, _ error) {
45-
4644
loc := protocol.Location{URI: fh.URI(), Range: rng}
4745

4846
pgf, err := snapshot.ParseGo(ctx, fh, parsego.Full)
@@ -341,7 +339,7 @@ func quickFix(ctx context.Context, req *codeActionsRequest) error {
341339
} else {
342340
// Offer a "Declare missing field T.f" code action.
343341
// See [stubMissingStructFieldFixer] for command implementation.
344-
fi := GetFieldStubInfo(req.pkg.FileSet(), info, path)
342+
fi := stubmethods.GetFieldStubInfo(req.pkg.FileSet(), info, path)
345343
if fi != nil {
346344
msg := fmt.Sprintf("Declare missing struct field %s.%s", fi.Named.Obj().Name(), fi.Expr.Sel.Name)
347345
req.addApplyFixAction(msg, fixMissingStructField, req.loc)
@@ -364,75 +362,6 @@ func quickFix(ctx context.Context, req *codeActionsRequest) error {
364362
return nil
365363
}
366364

367-
func GetFieldStubInfo(fset *token.FileSet, info *types.Info, path []ast.Node) *StructFieldInfo {
368-
for _, node := range path {
369-
n, ok := node.(*ast.SelectorExpr)
370-
if !ok {
371-
continue
372-
}
373-
tv, ok := info.Types[n.X]
374-
if !ok {
375-
break
376-
}
377-
378-
named, ok := tv.Type.(*types.Named)
379-
if !ok {
380-
break
381-
}
382-
383-
structType, ok := named.Underlying().(*types.Struct)
384-
if !ok {
385-
break
386-
}
387-
388-
return &StructFieldInfo{
389-
Fset: fset,
390-
Expr: n,
391-
Struct: structType,
392-
Named: named,
393-
Info: info,
394-
Path: path,
395-
}
396-
}
397-
398-
return nil
399-
}
400-
401-
type StructFieldInfo struct {
402-
Fset *token.FileSet
403-
Expr *ast.SelectorExpr
404-
Struct *types.Struct
405-
Named *types.Named
406-
Info *types.Info
407-
Path []ast.Node
408-
}
409-
410-
// Emit writes to out the missing field based on type info.
411-
func (si *StructFieldInfo) Emit(out *bytes.Buffer, qual types.Qualifier) error {
412-
if si.Expr == nil || si.Expr.Sel == nil {
413-
return fmt.Errorf("invalid selector expression")
414-
}
415-
416-
// Get types from context at the selector expression position
417-
typesFromContext := typesutil.TypesFromContext(si.Info, si.Path, si.Expr.Pos())
418-
419-
// Default to interface{} if we couldn't determine the type from context
420-
var fieldType types.Type
421-
if len(typesFromContext) > 0 && typesFromContext[0] != nil {
422-
fieldType = typesFromContext[0]
423-
} else {
424-
// Create a new interface{} type
425-
fieldType = types.NewInterfaceType(nil, nil)
426-
}
427-
428-
tpl := "\n\t%s %s"
429-
if si.Struct.NumFields() == 0 {
430-
tpl += "\n"
431-
}
432-
fmt.Fprintf(out, tpl, si.Expr.Sel.Name, types.TypeString(fieldType, qual))
433-
return nil
434-
}
435-
436365
// allImportsFixesResult is the result of a lazy call to allImportsFixes.
437366
// It implements the codeActionsRequest lazyInit interface.
438367
type allImportsFixesResult struct {

gopls/internal/golang/stub.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func stubMissingCalledFunctionFixer(ctx context.Context, snapshot *cache.Snapsho
5757
// at the cursor position.
5858
func stubMissingStructFieldFixer(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
5959
nodes, _ := astutil.PathEnclosingInterval(pgf.File, start, end)
60-
fi := GetFieldStubInfo(pkg.FileSet(), pkg.TypesInfo(), nodes)
60+
fi := stubmethods.GetFieldStubInfo(pkg.FileSet(), pkg.TypesInfo(), nodes)
6161
if fi == nil {
6262
return nil, nil, fmt.Errorf("invalid type request")
6363
}
@@ -252,7 +252,7 @@ func trimVersionSuffix(path string) string {
252252
return path
253253
}
254254

255-
func insertStructField(ctx context.Context, snapshot *cache.Snapshot, meta *metadata.Package, fieldInfo *StructFieldInfo) (*token.FileSet, *analysis.SuggestedFix, error) {
255+
func insertStructField(ctx context.Context, snapshot *cache.Snapshot, meta *metadata.Package, fieldInfo *stubmethods.StructFieldInfo) (*token.FileSet, *analysis.SuggestedFix, error) {
256256
if fieldInfo == nil {
257257
return nil, nil, fmt.Errorf("no field info provided")
258258
}
@@ -304,13 +304,11 @@ func insertStructField(ctx context.Context, snapshot *cache.Snapshot, meta *meta
304304
textEdit := analysis.TextEdit{
305305
Pos: insertPos,
306306
End: insertPos,
307-
NewText: []byte(buf.String()),
307+
NewText: buf.Bytes(),
308308
}
309309

310-
fix := &analysis.SuggestedFix{
310+
return fieldInfo.Fset, &analysis.SuggestedFix{
311311
Message: fmt.Sprintf("Add field %s to struct %s", fieldInfo.Expr.Sel.Name, fieldInfo.Named.Obj().Name()),
312312
TextEdits: []analysis.TextEdit{textEdit},
313-
}
314-
315-
return fieldInfo.Fset, fix, nil
313+
}, nil
316314
}

gopls/internal/golang/stubmethods/stubmethods.go

+72
Original file line numberDiff line numberDiff line change
@@ -450,3 +450,75 @@ func concreteType(e ast.Expr, info *types.Info) (*types.Named, bool) {
450450
}
451451
return named, isPtr
452452
}
453+
454+
func GetFieldStubInfo(fset *token.FileSet, info *types.Info, path []ast.Node) *StructFieldInfo {
455+
for _, node := range path {
456+
n, ok := node.(*ast.SelectorExpr)
457+
if !ok {
458+
continue
459+
}
460+
tv, ok := info.Types[n.X]
461+
if !ok {
462+
break
463+
}
464+
465+
named, ok := tv.Type.(*types.Named)
466+
if !ok {
467+
break
468+
}
469+
470+
structType, ok := named.Underlying().(*types.Struct)
471+
if !ok {
472+
break
473+
}
474+
475+
return &StructFieldInfo{
476+
Fset: fset,
477+
Expr: n,
478+
Struct: structType,
479+
Named: named,
480+
Info: info,
481+
Path: path,
482+
}
483+
}
484+
485+
return nil
486+
}
487+
488+
// StructFieldInfo describes f field in x.f where x has a named struct type
489+
type StructFieldInfo struct {
490+
Fset *token.FileSet
491+
Expr *ast.SelectorExpr
492+
Struct *types.Struct
493+
Named *types.Named
494+
Info *types.Info
495+
Path []ast.Node
496+
}
497+
498+
// Emit writes to out the missing field based on type info.
499+
func (si *StructFieldInfo) Emit(out *bytes.Buffer, qual types.Qualifier) error {
500+
if si.Expr == nil || si.Expr.Sel == nil {
501+
return fmt.Errorf("invalid selector expression")
502+
}
503+
504+
// Get types from context at the selector expression position
505+
typesFromContext := typesutil.TypesFromContext(si.Info, si.Path, si.Expr.Pos())
506+
507+
// Default to interface{} if we couldn't determine the type from context
508+
var fieldType types.Type
509+
if len(typesFromContext) > 0 {
510+
fieldType = typesFromContext[0]
511+
} else {
512+
// Create a new interface{} type
513+
fieldType = types.Universe.Lookup("any").Type()
514+
}
515+
516+
out.Write([]byte{'\n', '\t'})
517+
out.WriteString(si.Expr.Sel.Name)
518+
out.WriteByte(' ')
519+
out.WriteString(types.TypeString(fieldType, qual))
520+
if si.Struct.NumFields() == 0 {
521+
out.WriteByte('\n')
522+
}
523+
return nil
524+
}

gopls/internal/util/typesutil/typesutil.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,9 @@ func TypesFromContext(info *types.Info, path []ast.Node, pos token.Pos) []types.
186186
}
187187
case *ast.SelectorExpr:
188188
for _, n := range path {
189-
assignExpr, ok := n.(*ast.AssignStmt)
189+
assign, ok := n.(*ast.AssignStmt)
190190
if ok {
191-
for _, rh := range assignExpr.Rhs {
191+
for _, rh := range assign.Rhs {
192192
// basic types
193193
basicLit, ok := rh.(*ast.BasicLit)
194194
if ok {

0 commit comments

Comments
 (0)