X-Git-Url: https://git.josue.xyz/?p=dotfiles%2F.git;a=blobdiff_plain;f=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201105173854-bc9fc8d8c4bc%2Finternal%2Flsp%2Fcache%2Fmod_tidy.go;fp=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201105173854-bc9fc8d8c4bc%2Finternal%2Flsp%2Fcache%2Fmod_tidy.go;h=0000000000000000000000000000000000000000;hp=76479ee05c7e8ff8e9c40059175e0743b9b2f64d;hb=3ddadb3c98564791f0ac36cb39771d844a63dc91;hpb=5f797af6612ed10887189b47a1efc2f915586e59 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 index 76479ee0..00000000 --- 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 +++ /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)) -}