github.com/jd-ly/tools@v0.5.7/internal/lsp/mod/diagnostics.go (about)

     1  // Copyright 2019 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 mod provides core features related to go.mod file
     6  // handling for use by Go editors and tools.
     7  package mod
     8  
     9  import (
    10  	"context"
    11  
    12  	"github.com/jd-ly/tools/internal/event"
    13  	"github.com/jd-ly/tools/internal/lsp/debug/tag"
    14  	"github.com/jd-ly/tools/internal/lsp/protocol"
    15  	"github.com/jd-ly/tools/internal/lsp/source"
    16  	errors "golang.org/x/xerrors"
    17  )
    18  
    19  func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
    20  	ctx, done := event.Start(ctx, "mod.Diagnostics", tag.Snapshot.Of(snapshot.ID()))
    21  	defer done()
    22  
    23  	reports := map[source.VersionedFileIdentity][]*source.Diagnostic{}
    24  	for _, uri := range snapshot.ModFiles() {
    25  		fh, err := snapshot.GetVersionedFile(ctx, uri)
    26  		if err != nil {
    27  			return nil, err
    28  		}
    29  		reports[fh.VersionedFileIdentity()] = []*source.Diagnostic{}
    30  		errors, err := ErrorsForMod(ctx, snapshot, fh)
    31  		if err != nil {
    32  			return nil, err
    33  		}
    34  		for _, e := range errors {
    35  			d := &source.Diagnostic{
    36  				Message: e.Message,
    37  				Range:   e.Range,
    38  				Source:  e.Category,
    39  			}
    40  			if e.Category == "syntax" || e.Kind == source.ListError {
    41  				d.Severity = protocol.SeverityError
    42  			} else {
    43  				d.Severity = protocol.SeverityWarning
    44  			}
    45  			fh, err := snapshot.GetVersionedFile(ctx, e.URI)
    46  			if err != nil {
    47  				return nil, err
    48  			}
    49  			reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], d)
    50  		}
    51  	}
    52  	return reports, nil
    53  }
    54  
    55  func ErrorsForMod(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]*source.Error, error) {
    56  	pm, err := snapshot.ParseMod(ctx, fh)
    57  	if err != nil {
    58  		if pm == nil || len(pm.ParseErrors) == 0 {
    59  			return nil, err
    60  		}
    61  		return pm.ParseErrors, nil
    62  	}
    63  	tidied, err := snapshot.ModTidy(ctx, pm)
    64  
    65  	if source.IsNonFatalGoModError(err) {
    66  		return nil, nil
    67  	}
    68  	if err != nil {
    69  		// Some error messages can also be displayed as diagnostics.
    70  		if criticalErr := (*source.CriticalError)(nil); errors.As(err, &criticalErr) {
    71  			return criticalErr.ErrorList, nil
    72  		} else if srcErrList := (source.ErrorList)(nil); errors.As(err, &srcErrList) {
    73  			return srcErrList, nil
    74  		}
    75  		return nil, err
    76  	}
    77  	return tidied.Errors, nil
    78  }