some deletions
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / cache / mod_tidy.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/mod_tidy.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/mod_tidy.go
deleted file mode 100644 (file)
index 76479ee..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-// 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 cache
-
-import (
-       "context"
-       "fmt"
-       "go/ast"
-       "io/ioutil"
-       "os"
-       "path/filepath"
-       "sort"
-       "strconv"
-       "strings"
-
-       "golang.org/x/mod/modfile"
-       "golang.org/x/tools/internal/event"
-       "golang.org/x/tools/internal/gocommand"
-       "golang.org/x/tools/internal/lsp/debug/tag"
-       "golang.org/x/tools/internal/lsp/diff"
-       "golang.org/x/tools/internal/lsp/protocol"
-       "golang.org/x/tools/internal/lsp/source"
-       "golang.org/x/tools/internal/memoize"
-       "golang.org/x/tools/internal/span"
-)
-
-type modTidyKey struct {
-       sessionID       string
-       env             string
-       gomod           source.FileIdentity
-       imports         string
-       unsavedOverlays string
-       view            string
-}
-
-type modTidyHandle struct {
-       handle *memoize.Handle
-}
-
-type modTidyData struct {
-       tidied *source.TidiedModule
-       err    error
-}
-
-func (mth *modTidyHandle) tidy(ctx context.Context, snapshot *snapshot) (*source.TidiedModule, error) {
-       v, err := mth.handle.Get(ctx, snapshot.generation, snapshot)
-       if err != nil {
-               return nil, err
-       }
-       data := v.(*modTidyData)
-       return data.tidied, data.err
-}
-
-func (s *snapshot) ModTidy(ctx context.Context, fh source.FileHandle) (*source.TidiedModule, error) {
-       if fh.Kind() != source.Mod {
-               return nil, fmt.Errorf("%s is not a go.mod file", fh.URI())
-       }
-       if handle := s.getModTidyHandle(fh.URI()); handle != nil {
-               return handle.tidy(ctx, s)
-       }
-       // If the file handle is an overlay, it may not be written to disk.
-       // The go.mod file has to be on disk for `go mod tidy` to work.
-       if _, ok := fh.(*overlay); ok {
-               if info, _ := os.Stat(fh.URI().Filename()); info == nil {
-                       return nil, source.ErrNoModOnDisk
-               }
-       }
-       workspacePkgs, err := s.WorkspacePackages(ctx)
-       if err != nil {
-               if tm, ok := s.parseModErrors(ctx, fh, err); ok {
-                       return tm, nil
-               }
-               return nil, err
-       }
-       importHash, err := hashImports(ctx, workspacePkgs)
-       if err != nil {
-               return nil, err
-       }
-
-       s.mu.Lock()
-       overlayHash := hashUnsavedOverlays(s.files)
-       s.mu.Unlock()
-
-       key := modTidyKey{
-               sessionID:       s.view.session.id,
-               view:            s.view.folder.Filename(),
-               imports:         importHash,
-               unsavedOverlays: overlayHash,
-               gomod:           fh.FileIdentity(),
-               env:             hashEnv(s),
-       }
-       h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
-               ctx, done := event.Start(ctx, "cache.ModTidyHandle", tag.URI.Of(fh.URI()))
-               defer done()
-
-               snapshot := arg.(*snapshot)
-               pm, err := snapshot.ParseMod(ctx, fh)
-               if err != nil || len(pm.ParseErrors) > 0 {
-                       if err == nil {
-                               err = fmt.Errorf("could not parse module to tidy: %v", pm.ParseErrors)
-                       }
-                       var errors []source.Error
-                       if pm != nil {
-                               errors = pm.ParseErrors
-                       }
-                       return &modTidyData{
-                               tidied: &source.TidiedModule{
-                                       Parsed: pm,
-                                       Errors: errors,
-                               },
-                               err: err,
-                       }
-               }
-               inv := &gocommand.Invocation{
-                       Verb:       "mod",
-                       Args:       []string{"tidy"},
-                       WorkingDir: filepath.Dir(fh.URI().Filename()),
-               }
-               tmpURI, inv, cleanup, err := snapshot.goCommandInvocation(ctx, source.WriteTemporaryModFile, inv)
-               if err != nil {
-                       return &modTidyData{err: err}
-               }
-               // Keep the temporary go.mod file around long enough to parse it.
-               defer cleanup()
-
-               if _, err := s.view.session.gocmdRunner.Run(ctx, *inv); err != nil {
-                       return &modTidyData{err: err}
-               }
-               // Go directly to disk to get the temporary mod file, since it is
-               // always on disk.
-               tempContents, err := ioutil.ReadFile(tmpURI.Filename())
-               if err != nil {
-                       return &modTidyData{err: err}
-               }
-               ideal, err := modfile.Parse(tmpURI.Filename(), tempContents, nil)
-               if err != nil {
-                       // We do not need to worry about the temporary file's parse errors
-                       // since it has been "tidied".
-                       return &modTidyData{err: err}
-               }
-               // Compare the original and tidied go.mod files to compute errors and
-               // suggested fixes.
-               errors, err := modTidyErrors(ctx, snapshot, pm, ideal, workspacePkgs)
-               if err != nil {
-                       return &modTidyData{err: err}
-               }
-               return &modTidyData{
-                       tidied: &source.TidiedModule{
-                               Errors:        errors,
-                               Parsed:        pm,
-                               TidiedContent: tempContents,
-                       },
-               }
-       }, nil)
-
-       mth := &modTidyHandle{handle: h}
-       s.mu.Lock()
-       s.modTidyHandles[fh.URI()] = mth
-       s.mu.Unlock()
-
-       return mth.tidy(ctx, s)
-}
-
-func (s *snapshot) parseModErrors(ctx context.Context, fh source.FileHandle, err error) (*source.TidiedModule, bool) {
-       if err == nil {
-               return nil, false
-       }
-       switch {
-       // Match on common error messages. This is really hacky, but I'm not sure
-       // of any better way. This can be removed when golang/go#39164 is resolved.
-       case strings.Contains(err.Error(), "inconsistent vendoring"):
-               pmf, err := s.ParseMod(ctx, fh)
-               if err != nil {
-                       return nil, false
-               }
-               if pmf.File.Module == nil || pmf.File.Module.Syntax == nil {
-                       return nil, false
-               }
-               rng, err := rangeFromPositions(pmf.Mapper, pmf.File.Module.Syntax.Start, pmf.File.Module.Syntax.End)
-               if err != nil {
-                       return nil, false
-               }
-               args, err := source.MarshalArgs(protocol.URIFromSpanURI(fh.URI()))
-               if err != nil {
-                       return nil, false
-               }
-               return &source.TidiedModule{
-                       Parsed: pmf,
-                       Errors: []source.Error{{
-                               URI:   fh.URI(),
-                               Range: rng,
-                               Kind:  source.ListError,
-                               Message: `Inconsistent vendoring detected. Please re-run "go mod vendor".
-See https://github.com/golang/go/issues/39164 for more detail on this issue.`,
-                               SuggestedFixes: []source.SuggestedFix{{
-                                       Command: &protocol.Command{
-                                               Command:   source.CommandVendor.ID(),
-                                               Title:     source.CommandVendor.Title,
-                                               Arguments: args,
-                                       },
-                               }},
-                       }},
-               }, true
-       }
-       return nil, false
-}
-
-func hashImports(ctx context.Context, wsPackages []source.Package) (string, error) {
-       results := make(map[string]bool)
-       var imports []string
-       for _, pkg := range wsPackages {
-               for _, path := range pkg.Imports() {
-                       imp := path.PkgPath()
-                       if _, ok := results[imp]; !ok {
-                               results[imp] = true
-                               imports = append(imports, imp)
-                       }
-               }
-       }
-       sort.Strings(imports)
-       hashed := strings.Join(imports, ",")
-       return hashContents([]byte(hashed)), nil
-}
-
-// modTidyErrors computes the differences between the original and tidied
-// go.mod files to produce diagnostic and suggested fixes. Some diagnostics
-// may appear on the Go files that import packages from missing modules.
-func modTidyErrors(ctx context.Context, snapshot source.Snapshot, pm *source.ParsedModule, ideal *modfile.File, workspacePkgs []source.Package) (errors []source.Error, err error) {
-       // First, determine which modules are unused and which are missing from the
-       // original go.mod file.
-       var (
-               unused          = make(map[string]*modfile.Require, len(pm.File.Require))
-               missing         = make(map[string]*modfile.Require, len(ideal.Require))
-               wrongDirectness = make(map[string]*modfile.Require, len(pm.File.Require))
-       )
-       for _, req := range pm.File.Require {
-               unused[req.Mod.Path] = req
-       }
-       for _, req := range ideal.Require {
-               origReq := unused[req.Mod.Path]
-               if origReq == nil {
-                       missing[req.Mod.Path] = req
-                       continue
-               } else if origReq.Indirect != req.Indirect {
-                       wrongDirectness[req.Mod.Path] = origReq
-               }
-               delete(unused, req.Mod.Path)
-       }
-       for _, req := range unused {
-               srcErr, err := unusedError(pm.Mapper, req, snapshot.View().Options().ComputeEdits)
-               if err != nil {
-                       return nil, err
-               }
-               errors = append(errors, srcErr)
-       }
-       for _, req := range wrongDirectness {
-               // Handle dependencies that are incorrectly labeled indirect and
-               // vice versa.
-               srcErr, err := directnessError(pm.Mapper, req, snapshot.View().Options().ComputeEdits)
-               if err != nil {
-                       return nil, err
-               }
-               errors = append(errors, srcErr)
-       }
-       // Next, compute any diagnostics for modules that are missing from the
-       // go.mod file. The fixes will be for the go.mod file, but the
-       // diagnostics should also appear in both the go.mod file and the import
-       // statements in the Go files in which the dependencies are used.
-       missingModuleFixes := map[*modfile.Require][]source.SuggestedFix{}
-       for _, req := range missing {
-               srcErr, err := missingModuleError(snapshot, pm, req)
-               if err != nil {
-                       return nil, err
-               }
-               missingModuleFixes[req] = srcErr.SuggestedFixes
-               errors = append(errors, srcErr)
-       }
-       // Add diagnostics for missing modules anywhere they are imported in the
-       // workspace.
-       for _, pkg := range workspacePkgs {
-               missingImports := map[string]*modfile.Require{}
-               for _, imp := range pkg.Imports() {
-                       if req, ok := missing[imp.PkgPath()]; ok {
-                               missingImports[imp.PkgPath()] = req
-                               break
-                       }
-                       // If the import is a package of the dependency, then add the
-                       // package to the map, this will eliminate the need to do this
-                       // prefix package search on each import for each file.
-                       // Example:
-                       //
-                       // import (
-                       //   "golang.org/x/tools/go/expect"
-                       //   "golang.org/x/tools/go/packages"
-                       // )
-                       // They both are related to the same module: "golang.org/x/tools".
-                       var match string
-                       for _, req := range ideal.Require {
-                               if strings.HasPrefix(imp.PkgPath(), req.Mod.Path) && len(req.Mod.Path) > len(match) {
-                                       match = req.Mod.Path
-                               }
-                       }
-                       if req, ok := missing[match]; ok {
-                               missingImports[imp.PkgPath()] = req
-                       }
-               }
-               // None of this package's imports are from missing modules.
-               if len(missingImports) == 0 {
-                       continue
-               }
-               for _, pgf := range pkg.CompiledGoFiles() {
-                       file, m := pgf.File, pgf.Mapper
-                       if file == nil || m == nil {
-                               continue
-                       }
-                       imports := make(map[string]*ast.ImportSpec)
-                       for _, imp := range file.Imports {
-                               if imp.Path == nil {
-                                       continue
-                               }
-                               if target, err := strconv.Unquote(imp.Path.Value); err == nil {
-                                       imports[target] = imp
-                               }
-                       }
-                       if len(imports) == 0 {
-                               continue
-                       }
-                       for importPath, req := range missingImports {
-                               imp, ok := imports[importPath]
-                               if !ok {
-                                       continue
-                               }
-                               fixes, ok := missingModuleFixes[req]
-                               if !ok {
-                                       return nil, fmt.Errorf("no missing module fix for %q (%q)", importPath, req.Mod.Path)
-                               }
-                               srcErr, err := missingModuleForImport(snapshot, m, imp, req, fixes)
-                               if err != nil {
-                                       return nil, err
-                               }
-                               errors = append(errors, srcErr)
-                       }
-               }
-       }
-       return errors, nil
-}
-
-// unusedError returns a source.Error for an unused require.
-func unusedError(m *protocol.ColumnMapper, req *modfile.Require, computeEdits diff.ComputeEdits) (source.Error, error) {
-       rng, err := rangeFromPositions(m, req.Syntax.Start, req.Syntax.End)
-       if err != nil {
-               return source.Error{}, err
-       }
-       args, err := source.MarshalArgs(m.URI, false, []string{req.Mod.Path + "@none"})
-       if err != nil {
-               return source.Error{}, err
-       }
-       return source.Error{
-               Category: source.GoModTidy,
-               Message:  fmt.Sprintf("%s is not used in this module", req.Mod.Path),
-               Range:    rng,
-               URI:      m.URI,
-               SuggestedFixes: []source.SuggestedFix{{
-                       Title: fmt.Sprintf("Remove dependency: %s", req.Mod.Path),
-                       Command: &protocol.Command{
-                               Title:     source.CommandRemoveDependency.Title,
-                               Command:   source.CommandRemoveDependency.ID(),
-                               Arguments: args,
-                       },
-               }},
-       }, nil
-}
-
-// directnessError extracts errors when a dependency is labeled indirect when
-// it should be direct and vice versa.
-func directnessError(m *protocol.ColumnMapper, req *modfile.Require, computeEdits diff.ComputeEdits) (source.Error, error) {
-       rng, err := rangeFromPositions(m, req.Syntax.Start, req.Syntax.End)
-       if err != nil {
-               return source.Error{}, err
-       }
-       direction := "indirect"
-       if req.Indirect {
-               direction = "direct"
-
-               // If the dependency should be direct, just highlight the // indirect.
-               if comments := req.Syntax.Comment(); comments != nil && len(comments.Suffix) > 0 {
-                       end := comments.Suffix[0].Start
-                       end.LineRune += len(comments.Suffix[0].Token)
-                       end.Byte += len([]byte(comments.Suffix[0].Token))
-                       rng, err = rangeFromPositions(m, comments.Suffix[0].Start, end)
-                       if err != nil {
-                               return source.Error{}, err
-                       }
-               }
-       }
-       // If the dependency should be indirect, add the // indirect.
-       edits, err := switchDirectness(req, m, computeEdits)
-       if err != nil {
-               return source.Error{}, err
-       }
-       return source.Error{
-               Message:  fmt.Sprintf("%s should be %s", req.Mod.Path, direction),
-               Range:    rng,
-               URI:      m.URI,
-               Category: source.GoModTidy,
-               SuggestedFixes: []source.SuggestedFix{{
-                       Title: fmt.Sprintf("Change %s to %s", req.Mod.Path, direction),
-                       Edits: map[span.URI][]protocol.TextEdit{
-                               m.URI: edits,
-                       },
-               }},
-       }, nil
-}
-
-func missingModuleError(snapshot source.Snapshot, pm *source.ParsedModule, req *modfile.Require) (source.Error, error) {
-       var rng protocol.Range
-       // Default to the start of the file if there is no module declaration.
-       if pm.File != nil && pm.File.Module != nil && pm.File.Module.Syntax != nil {
-               start, end := pm.File.Module.Syntax.Span()
-               var err error
-               rng, err = rangeFromPositions(pm.Mapper, start, end)
-               if err != nil {
-                       return source.Error{}, err
-               }
-       }
-       args, err := source.MarshalArgs(pm.Mapper.URI, !req.Indirect, []string{req.Mod.Path + "@" + req.Mod.Version})
-       if err != nil {
-               return source.Error{}, err
-       }
-       return source.Error{
-               URI:      pm.Mapper.URI,
-               Range:    rng,
-               Message:  fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
-               Category: source.GoModTidy,
-               Kind:     source.ModTidyError,
-               SuggestedFixes: []source.SuggestedFix{{
-                       Title: fmt.Sprintf("Add %s to your go.mod file", req.Mod.Path),
-                       Command: &protocol.Command{
-                               Title:     source.CommandAddDependency.Title,
-                               Command:   source.CommandAddDependency.ID(),
-                               Arguments: args,
-                       },
-               }},
-       }, nil
-}
-
-// switchDirectness gets the edits needed to change an indirect dependency to
-// direct and vice versa.
-func switchDirectness(req *modfile.Require, m *protocol.ColumnMapper, computeEdits diff.ComputeEdits) ([]protocol.TextEdit, error) {
-       // We need a private copy of the parsed go.mod file, since we're going to
-       // modify it.
-       copied, err := modfile.Parse("", m.Content, nil)
-       if err != nil {
-               return nil, err
-       }
-       // Change the directness in the matching require statement. To avoid
-       // reordering the require statements, rewrite all of them.
-       var requires []*modfile.Require
-       for _, r := range copied.Require {
-               if r.Mod.Path == req.Mod.Path {
-                       requires = append(requires, &modfile.Require{
-                               Mod:      r.Mod,
-                               Syntax:   r.Syntax,
-                               Indirect: !r.Indirect,
-                       })
-                       continue
-               }
-               requires = append(requires, r)
-       }
-       copied.SetRequire(requires)
-       newContent, err := copied.Format()
-       if err != nil {
-               return nil, err
-       }
-       // Calculate the edits to be made due to the change.
-       diff := computeEdits(m.URI, string(m.Content), string(newContent))
-       return source.ToProtocolEdits(m, diff)
-}
-
-// missingModuleForImport creates an error for a given import path that comes
-// from a missing module.
-func missingModuleForImport(snapshot source.Snapshot, m *protocol.ColumnMapper, imp *ast.ImportSpec, req *modfile.Require, fixes []source.SuggestedFix) (source.Error, error) {
-       if req.Syntax == nil {
-               return source.Error{}, fmt.Errorf("no syntax for %v", req)
-       }
-       spn, err := span.NewRange(snapshot.FileSet(), imp.Path.Pos(), imp.Path.End()).Span()
-       if err != nil {
-               return source.Error{}, err
-       }
-       rng, err := m.Range(spn)
-       if err != nil {
-               return source.Error{}, err
-       }
-       return source.Error{
-               Category:       source.GoModTidy,
-               URI:            m.URI,
-               Range:          rng,
-               Message:        fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
-               Kind:           source.ModTidyError,
-               SuggestedFixes: fixes,
-       }, nil
-}
-
-func rangeFromPositions(m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) {
-       toPoint := func(offset int) (span.Point, error) {
-               l, c, err := m.Converter.ToPosition(offset)
-               if err != nil {
-                       return span.Point{}, err
-               }
-               return span.NewPoint(l, c, offset), nil
-       }
-       start, err := toPoint(s.Byte)
-       if err != nil {
-               return protocol.Range{}, err
-       }
-       end, err := toPoint(e.Byte)
-       if err != nil {
-               return protocol.Range{}, err
-       }
-       return m.Range(span.New(m.URI, start, end))
-}