github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/analysis/edit/edit.go (about)

     1  // Package edit contains helpers for creating suggested fixes.
     2  package edit
     3  
     4  import (
     5  	"bytes"
     6  	"go/ast"
     7  	"go/format"
     8  	"go/token"
     9  
    10  	"github.com/amarpal/go-tools/pattern"
    11  	"golang.org/x/tools/go/analysis"
    12  )
    13  
    14  // Ranger describes values that have a start and end position.
    15  // In most cases these are either ast.Node or manually constructed ranges.
    16  type Ranger interface {
    17  	Pos() token.Pos
    18  	End() token.Pos
    19  }
    20  
    21  // Range implements the Ranger interface.
    22  type Range [2]token.Pos
    23  
    24  func (r Range) Pos() token.Pos { return r[0] }
    25  func (r Range) End() token.Pos { return r[1] }
    26  
    27  // ReplaceWithString replaces a range with a string.
    28  func ReplaceWithString(old Ranger, new string) analysis.TextEdit {
    29  	return analysis.TextEdit{
    30  		Pos:     old.Pos(),
    31  		End:     old.End(),
    32  		NewText: []byte(new),
    33  	}
    34  }
    35  
    36  // ReplaceWithNode replaces a range with an AST node.
    37  func ReplaceWithNode(fset *token.FileSet, old Ranger, new ast.Node) analysis.TextEdit {
    38  	buf := &bytes.Buffer{}
    39  	if err := format.Node(buf, fset, new); err != nil {
    40  		panic("internal error: " + err.Error())
    41  	}
    42  	return analysis.TextEdit{
    43  		Pos:     old.Pos(),
    44  		End:     old.End(),
    45  		NewText: buf.Bytes(),
    46  	}
    47  }
    48  
    49  // ReplaceWithPattern replaces a range with the result of executing a pattern.
    50  func ReplaceWithPattern(fset *token.FileSet, old Ranger, new pattern.Pattern, state pattern.State) analysis.TextEdit {
    51  	r := pattern.NodeToAST(new.Root, state)
    52  	buf := &bytes.Buffer{}
    53  	format.Node(buf, fset, r)
    54  	return analysis.TextEdit{
    55  		Pos:     old.Pos(),
    56  		End:     old.End(),
    57  		NewText: buf.Bytes(),
    58  	}
    59  }
    60  
    61  // Delete deletes a range of code.
    62  func Delete(old Ranger) analysis.TextEdit {
    63  	return analysis.TextEdit{
    64  		Pos:     old.Pos(),
    65  		End:     old.End(),
    66  		NewText: nil,
    67  	}
    68  }
    69  
    70  func Fix(msg string, edits ...analysis.TextEdit) analysis.SuggestedFix {
    71  	return analysis.SuggestedFix{
    72  		Message:   msg,
    73  		TextEdits: edits,
    74  	}
    75  }
    76  
    77  // Selector creates a new selector expression.
    78  func Selector(x, sel string) *ast.SelectorExpr {
    79  	return &ast.SelectorExpr{
    80  		X:   &ast.Ident{Name: x},
    81  		Sel: &ast.Ident{Name: sel},
    82  	}
    83  }