Skip to content

Commit bb7aa66

Browse files
committed
Move GetFieldStubInfo to stubmethods package
1 parent 5f30384 commit bb7aa66

File tree

4 files changed

+82
-82
lines changed

4 files changed

+82
-82
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)
@@ -335,7 +333,7 @@ func quickFix(ctx context.Context, req *codeActionsRequest) error {
335333
} else {
336334
// Offer a "Declare missing field T.f" code action.
337335
// See [stubMissingStructFieldFixer] for command implementation.
338-
fi := GetFieldStubInfo(req.pkg.FileSet(), info, path)
336+
fi := stubmethods.GetFieldStubInfo(req.pkg.FileSet(), info, path)
339337
if fi != nil {
340338
msg := fmt.Sprintf("Declare missing struct field %s.%s", fi.Named.Obj().Name(), fi.Expr.Sel.Name)
341339
req.addApplyFixAction(msg, fixMissingStructField, req.loc)
@@ -358,75 +356,6 @@ func quickFix(ctx context.Context, req *codeActionsRequest) error {
358356
return nil
359357
}
360358

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

+74-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import (
1313
"go/ast"
1414
"go/token"
1515
"go/types"
16-
"golang.org/x/tools/internal/typesinternal"
1716
"strings"
1817

18+
"golang.org/x/tools/internal/typesinternal"
19+
1920
"golang.org/x/tools/gopls/internal/util/typesutil"
2021
)
2122

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

gopls/internal/util/typesutil/typesutil.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@ func TypesFromContext(info *types.Info, path []ast.Node, pos token.Pos) []types.
212212
}
213213
case *ast.SelectorExpr:
214214
for _, n := range path {
215-
assignExpr, ok := n.(*ast.AssignStmt)
215+
assign, ok := n.(*ast.AssignStmt)
216216
if ok {
217-
for _, rh := range assignExpr.Rhs {
217+
for _, rh := range assign.Rhs {
218218
// basic types
219219
basicLit, ok := rh.(*ast.BasicLit)
220220
if ok {

0 commit comments

Comments
 (0)