1
0
mirror of https://github.com/golang/go synced 2024-11-18 15:34:53 -07:00
go/internal/lsp/mod/code_lens.go
Rebecca Stambler 7b4c4ad3dc internal/lsp: correctly marshal arguments for upgrade code lens
I'm not sure how the regtest didn't catch this - is it possible that
it could unmarshal a single string a slice of string? Either way, I'd
like to get the fix in quicker - I'll try to add more regtests for this
later.

Also, validate the upgrade results more thoroughly.

Change-Id: I812a3fecd9f0642a1408c0a9c0376bb98d50b397
Reviewed-on: https://go-review.googlesource.com/c/tools/+/245065
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
2020-07-27 21:52:59 +00:00

116 lines
3.1 KiB
Go

package mod
import (
"context"
"fmt"
"golang.org/x/mod/modfile"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/lsp/debug/tag"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
)
// CodeLens computes code lens for a go.mod file.
func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]protocol.CodeLens, error) {
if !snapshot.View().Options().EnabledCodeLens[source.CommandUpgradeDependency.Name] {
return nil, nil
}
ctx, done := event.Start(ctx, "mod.CodeLens", tag.URI.Of(uri))
defer done()
// Only show go.mod code lenses in module mode, for the view's go.mod.
if modURI := snapshot.View().ModFile(); modURI == "" || modURI != uri {
return nil, nil
}
fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
pmh, err := snapshot.ParseModHandle(ctx, fh)
if err != nil {
return nil, err
}
file, m, _, err := pmh.Parse(ctx)
if err != nil {
return nil, err
}
muh, err := snapshot.ModUpgradeHandle(ctx)
if err != nil {
return nil, err
}
upgrades, err := muh.Upgrades(ctx)
if err != nil {
return nil, err
}
var (
codelens []protocol.CodeLens
allUpgrades []string
)
for _, req := range file.Require {
dep := req.Mod.Path
latest, ok := upgrades[dep]
if !ok {
continue
}
// Get the range of the require directive.
rng, err := positionsToRange(uri, m, req.Syntax.Start, req.Syntax.End)
if err != nil {
return nil, err
}
jsonArgs, err := source.MarshalArgs(uri, []string{dep})
if err != nil {
return nil, err
}
codelens = append(codelens, protocol.CodeLens{
Range: rng,
Command: protocol.Command{
Title: fmt.Sprintf("Upgrade dependency to %s", latest),
Command: source.CommandUpgradeDependency.Name,
Arguments: jsonArgs,
},
})
allUpgrades = append(allUpgrades, dep)
}
// If there is at least 1 upgrade, add an "Upgrade all dependencies" to the module statement.
if module := file.Module; len(allUpgrades) > 0 && module != nil && module.Syntax != nil {
// Get the range of the module directive.
rng, err := positionsToRange(uri, m, module.Syntax.Start, module.Syntax.End)
if err != nil {
return nil, err
}
jsonArgs, err := source.MarshalArgs(uri, append([]string{"-u"}, allUpgrades...))
if err != nil {
return nil, err
}
codelens = append(codelens, protocol.CodeLens{
Range: rng,
Command: protocol.Command{
Title: "Upgrade all dependencies",
Command: source.CommandUpgradeDependency.Name,
Arguments: jsonArgs,
},
})
}
return codelens, err
}
func positionsToRange(uri span.URI, m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) {
line, col, err := m.Converter.ToPosition(s.Byte)
if err != nil {
return protocol.Range{}, err
}
start := span.NewPoint(line, col, s.Byte)
line, col, err = m.Converter.ToPosition(e.Byte)
if err != nil {
return protocol.Range{}, err
}
end := span.NewPoint(line, col, e.Byte)
rng, err := m.Range(span.New(uri, start, end))
if err != nil {
return protocol.Range{}, err
}
return rng, err
}