github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/work/diagnostics.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package work 6 7 import ( 8 "context" 9 "fmt" 10 "os" 11 "path/filepath" 12 13 "golang.org/x/mod/modfile" 14 "github.com/powerman/golang-tools/internal/event" 15 "github.com/powerman/golang-tools/internal/lsp/debug/tag" 16 "github.com/powerman/golang-tools/internal/lsp/protocol" 17 "github.com/powerman/golang-tools/internal/lsp/source" 18 "github.com/powerman/golang-tools/internal/span" 19 ) 20 21 func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) { 22 ctx, done := event.Start(ctx, "work.Diagnostics", tag.Snapshot.Of(snapshot.ID())) 23 defer done() 24 25 reports := map[source.VersionedFileIdentity][]*source.Diagnostic{} 26 uri := snapshot.WorkFile() 27 if uri == "" { 28 return nil, nil 29 } 30 fh, err := snapshot.GetVersionedFile(ctx, uri) 31 if err != nil { 32 return nil, err 33 } 34 reports[fh.VersionedFileIdentity()] = []*source.Diagnostic{} 35 diagnostics, err := DiagnosticsForWork(ctx, snapshot, fh) 36 if err != nil { 37 return nil, err 38 } 39 for _, d := range diagnostics { 40 fh, err := snapshot.GetVersionedFile(ctx, d.URI) 41 if err != nil { 42 return nil, err 43 } 44 reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], d) 45 } 46 47 return reports, nil 48 } 49 50 func DiagnosticsForWork(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]*source.Diagnostic, error) { 51 pw, err := snapshot.ParseWork(ctx, fh) 52 if err != nil { 53 if pw == nil || len(pw.ParseErrors) == 0 { 54 return nil, err 55 } 56 return pw.ParseErrors, nil 57 } 58 59 // Add diagnostic if a directory does not contain a module. 60 var diagnostics []*source.Diagnostic 61 for _, use := range pw.File.Use { 62 rng, err := source.LineToRange(pw.Mapper, fh.URI(), use.Syntax.Start, use.Syntax.End) 63 if err != nil { 64 return nil, err 65 } 66 67 modfh, err := snapshot.GetFile(ctx, modFileURI(pw, use)) 68 if err != nil { 69 return nil, err 70 } 71 if _, err := modfh.Read(); err != nil && os.IsNotExist(err) { 72 diagnostics = append(diagnostics, &source.Diagnostic{ 73 URI: fh.URI(), 74 Range: rng, 75 Severity: protocol.SeverityError, 76 Source: source.UnknownError, // Do we need a new source for this? 77 Message: fmt.Sprintf("directory %v does not contain a module", use.Path), 78 }) 79 } 80 } 81 return diagnostics, nil 82 } 83 84 func modFileURI(pw *source.ParsedWorkFile, use *modfile.Use) span.URI { 85 workdir := filepath.Dir(pw.URI.Filename()) 86 87 modroot := filepath.FromSlash(use.Path) 88 if !filepath.IsAbs(modroot) { 89 modroot = filepath.Join(workdir, modroot) 90 } 91 92 return span.URIFromPath(filepath.Join(modroot, "go.mod")) 93 }