edit.go raw

   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  	"golang.org/x/tools/go/analysis"
  11  	"honnef.co/go/tools/pattern"
  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  }
  84