.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / source / code_lens.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/code_lens.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/code_lens.go
new file mode 100644 (file)
index 0000000..0ab857a
--- /dev/null
@@ -0,0 +1,244 @@
+// 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"
+       "go/ast"
+       "go/token"
+       "go/types"
+       "path/filepath"
+       "regexp"
+       "strings"
+
+       "golang.org/x/tools/internal/lsp/command"
+       "golang.org/x/tools/internal/lsp/protocol"
+       "golang.org/x/tools/internal/span"
+)
+
+type LensFunc func(context.Context, Snapshot, FileHandle) ([]protocol.CodeLens, error)
+
+// LensFuncs returns the supported lensFuncs for Go files.
+func LensFuncs() map[command.Command]LensFunc {
+       return map[command.Command]LensFunc{
+               command.Generate:      goGenerateCodeLens,
+               command.Test:          runTestCodeLens,
+               command.RegenerateCgo: regenerateCgoLens,
+               command.GCDetails:     toggleDetailsCodeLens,
+       }
+}
+
+var (
+       testRe      = regexp.MustCompile("^Test[^a-z]")
+       benchmarkRe = regexp.MustCompile("^Benchmark[^a-z]")
+)
+
+func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
+       codeLens := make([]protocol.CodeLens, 0)
+
+       fns, err := TestsAndBenchmarks(ctx, snapshot, fh)
+       if err != nil {
+               return nil, err
+       }
+       puri := protocol.URIFromSpanURI(fh.URI())
+       for _, fn := range fns.Tests {
+               cmd, err := command.NewTestCommand("run test", puri, []string{fn.Name}, nil)
+               if err != nil {
+                       return nil, err
+               }
+               rng := protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start}
+               codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: cmd})
+       }
+
+       for _, fn := range fns.Benchmarks {
+               cmd, err := command.NewTestCommand("run benchmark", puri, nil, []string{fn.Name})
+               if err != nil {
+                       return nil, err
+               }
+               rng := protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start}
+               codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: cmd})
+       }
+
+       if len(fns.Benchmarks) > 0 {
+               _, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
+               if err != nil {
+                       return nil, err
+               }
+               // add a code lens to the top of the file which runs all benchmarks in the file
+               rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
+               if err != nil {
+                       return nil, err
+               }
+               var benches []string
+               for _, fn := range fns.Benchmarks {
+                       benches = append(benches, fn.Name)
+               }
+               cmd, err := command.NewTestCommand("run file benchmarks", puri, nil, benches)
+               if err != nil {
+                       return nil, err
+               }
+               codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: cmd})
+       }
+       return codeLens, nil
+}
+
+type testFn struct {
+       Name string
+       Rng  protocol.Range
+}
+
+type testFns struct {
+       Tests      []testFn
+       Benchmarks []testFn
+}
+
+func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, fh FileHandle) (testFns, error) {
+       var out testFns
+
+       if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
+               return out, nil
+       }
+       pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
+       if err != nil {
+               return out, err
+       }
+
+       for _, d := range pgf.File.Decls {
+               fn, ok := d.(*ast.FuncDecl)
+               if !ok {
+                       continue
+               }
+
+               rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), fn.End()).Range()
+               if err != nil {
+                       return out, err
+               }
+
+               if matchTestFunc(fn, pkg, testRe, "T") {
+                       out.Tests = append(out.Tests, testFn{fn.Name.Name, rng})
+               }
+
+               if matchTestFunc(fn, pkg, benchmarkRe, "B") {
+                       out.Benchmarks = append(out.Benchmarks, testFn{fn.Name.Name, rng})
+               }
+       }
+
+       return out, nil
+}
+
+func matchTestFunc(fn *ast.FuncDecl, pkg Package, nameRe *regexp.Regexp, paramID string) bool {
+       // Make sure that the function name matches a test function.
+       if !nameRe.MatchString(fn.Name.Name) {
+               return false
+       }
+       info := pkg.GetTypesInfo()
+       if info == nil {
+               return false
+       }
+       obj := info.ObjectOf(fn.Name)
+       if obj == nil {
+               return false
+       }
+       sig, ok := obj.Type().(*types.Signature)
+       if !ok {
+               return false
+       }
+       // Test functions should have only one parameter.
+       if sig.Params().Len() != 1 {
+               return false
+       }
+
+       // Check the type of the only parameter
+       paramTyp, ok := sig.Params().At(0).Type().(*types.Pointer)
+       if !ok {
+               return false
+       }
+       named, ok := paramTyp.Elem().(*types.Named)
+       if !ok {
+               return false
+       }
+       namedObj := named.Obj()
+       if namedObj.Pkg().Path() != "testing" {
+               return false
+       }
+       return namedObj.Id() == paramID
+}
+
+func goGenerateCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
+       pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
+       if err != nil {
+               return nil, err
+       }
+       const ggDirective = "//go:generate"
+       for _, c := range pgf.File.Comments {
+               for _, l := range c.List {
+                       if !strings.HasPrefix(l.Text, ggDirective) {
+                               continue
+                       }
+                       rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, l.Pos(), l.Pos()+token.Pos(len(ggDirective))).Range()
+                       if err != nil {
+                               return nil, err
+                       }
+                       dir := protocol.URIFromSpanURI(span.URIFromPath(filepath.Dir(fh.URI().Filename())))
+                       nonRecursiveCmd, err := command.NewGenerateCommand("run go generate", command.GenerateArgs{Dir: dir, Recursive: false})
+                       if err != nil {
+                               return nil, err
+                       }
+                       recursiveCmd, err := command.NewGenerateCommand("run go generate ./...", command.GenerateArgs{Dir: dir, Recursive: true})
+                       if err != nil {
+                               return nil, err
+                       }
+                       return []protocol.CodeLens{
+                               {Range: rng, Command: recursiveCmd},
+                               {Range: rng, Command: nonRecursiveCmd},
+                       }, nil
+
+               }
+       }
+       return nil, nil
+}
+
+func regenerateCgoLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
+       pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
+       if err != nil {
+               return nil, err
+       }
+       var c *ast.ImportSpec
+       for _, imp := range pgf.File.Imports {
+               if imp.Path.Value == `"C"` {
+                       c = imp
+               }
+       }
+       if c == nil {
+               return nil, nil
+       }
+       rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, c.Pos(), c.EndPos).Range()
+       if err != nil {
+               return nil, err
+       }
+       puri := protocol.URIFromSpanURI(fh.URI())
+       cmd, err := command.NewRegenerateCgoCommand("regenerate cgo definitions", command.URIArg{URI: puri})
+       if err != nil {
+               return nil, err
+       }
+       return []protocol.CodeLens{{Range: rng, Command: cmd}}, nil
+}
+
+func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
+       _, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
+       if err != nil {
+               return nil, err
+       }
+       rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
+       if err != nil {
+               return nil, err
+       }
+       puri := protocol.URIFromSpanURI(fh.URI())
+       cmd, err := command.NewGCDetailsCommand("Toggle gc annotation details", puri)
+       if err != nil {
+               return nil, err
+       }
+       return []protocol.CodeLens{{Range: rng, Command: cmd}}, nil
+}