blob: 6b9f9204cd571aae7e5eda126a6ad7e8a0c85717 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package source
import (
"context"
"fmt"
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
)
// SuggestedFixFunc is a function used to get the suggested fixes for a given
// go/analysis.Analyzer. Some of the analyzers in internal/lsp/analysis are not
// efficient enough to include suggested fixes with their diagnostics, so we
// have to compute them separately. Such analyzers should provide a function
// with a signature of SuggestedFixFunc.
type SuggestedFixFunc func(*token.FileSet, token.Pos, []byte, *ast.File, *types.Package, *types.Info) (*analysis.SuggestedFix, error)
// CommandSuggestedFixes returns the text edits for a given file and
// SuggestedFixFunc. It can be used to execute any command that provides its
// edits through a SuggestedFixFunc.
func CommandSuggestedFixes(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range, fn SuggestedFixFunc) ([]protocol.TextDocumentEdit, error) {
pkg, pgh, err := getParsedFile(ctx, snapshot, fh, NarrowestPackageHandle)
if err != nil {
return nil, fmt.Errorf("getting file for Identifier: %w", err)
}
file, _, m, _, err := pgh.Cached()
if err != nil {
return nil, err
}
spn, err := m.RangeSpan(pRng)
if err != nil {
return nil, err
}
rng, err := spn.Range(m.Converter)
if err != nil {
return nil, err
}
content, err := fh.Read()
if err != nil {
return nil, err
}
fset := snapshot.View().Session().Cache().FileSet()
fix, err := fn(fset, rng.Start, content, file, pkg.GetTypes(), pkg.GetTypesInfo())
if err != nil {
return nil, err
}
var edits []protocol.TextDocumentEdit
for _, edit := range fix.TextEdits {
rng := span.NewRange(fset, edit.Pos, edit.End)
spn, err = rng.Span()
if err != nil {
return nil, nil
}
clRng, err := m.Range(spn)
if err != nil {
return nil, nil
}
edits = append(edits, protocol.TextDocumentEdit{
TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: fh.Version(),
TextDocumentIdentifier: protocol.TextDocumentIdentifier{
URI: protocol.URIFromSpanURI(fh.URI()),
},
},
Edits: []protocol.TextEdit{
{
Range: clRng,
NewText: string(edit.NewText),
},
},
})
}
return edits, nil
}