@@ -6,6 +6,7 @@ package cache
66
77import (
88 "context"
9+ "errors"
910 "fmt"
1011 "path/filepath"
1112 "regexp"
@@ -297,36 +298,68 @@ func (s *snapshot) ModWhy(ctx context.Context, fh source.FileHandle) (map[string
297298
298299// extractGoCommandError tries to parse errors that come from the go command
299300// and shape them into go.mod diagnostics.
300- func (s * snapshot ) extractGoCommandErrors (ctx context.Context , goCmdError string ) ([]* source.Diagnostic , error ) {
301- diagLocations := map [* source.ParsedModule ]span.Span {}
302- backupDiagLocations := map [* source.ParsedModule ]span.Span {}
303-
304- // The go command emits parse errors for completely invalid go.mod files.
305- // Those are reported by our own diagnostics and can be ignored here.
306- // As of writing, we are not aware of any other errors that include
307- // file/position information, so don't even try to find it.
308- if strings .Contains (goCmdError , "errors parsing go.mod" ) {
309- return nil , nil
301+ // TODO: rename this to 'load errors'
302+ func (s * snapshot ) extractGoCommandErrors (ctx context.Context , goCmdError error ) []* source.Diagnostic {
303+ if goCmdError == nil {
304+ return nil
305+ }
306+
307+ type locatedErr struct {
308+ spn span.Span
309+ msg string
310310 }
311+ diagLocations := map [* source.ParsedModule ]locatedErr {}
312+ backupDiagLocations := map [* source.ParsedModule ]locatedErr {}
313+
314+ // If moduleErrs is non-nil, go command errors are scoped to specific
315+ // modules.
316+ var moduleErrs * moduleErrorMap
317+ _ = errors .As (goCmdError , & moduleErrs )
311318
312319 // Match the error against all the mod files in the workspace.
313320 for _ , uri := range s .ModFiles () {
314321 fh , err := s .GetFile (ctx , uri )
315322 if err != nil {
316- return nil , err
323+ event .Error (ctx , "getting modfile for Go command error" , err )
324+ continue
317325 }
318326 pm , err := s .ParseMod (ctx , fh )
319327 if err != nil {
320- return nil , err
321- }
322- spn , found , err := s .matchErrorToModule (ctx , pm , goCmdError )
323- if err != nil {
324- return nil , err
328+ // Parsing errors are reported elsewhere
329+ return nil
325330 }
326- if found {
327- diagLocations [pm ] = spn
331+ var msgs []string // error messages to consider
332+ if moduleErrs != nil {
333+ if pm .File .Module != nil {
334+ for _ , mes := range moduleErrs .errs [pm .File .Module .Mod .Path ] {
335+ msgs = append (msgs , mes .Error ())
336+ }
337+ }
328338 } else {
329- backupDiagLocations [pm ] = spn
339+ msgs = append (msgs , goCmdError .Error ())
340+ }
341+ for _ , msg := range msgs {
342+ if strings .Contains (goCmdError .Error (), "errors parsing go.mod" ) {
343+ // The go command emits parse errors for completely invalid go.mod files.
344+ // Those are reported by our own diagnostics and can be ignored here.
345+ // As of writing, we are not aware of any other errors that include
346+ // file/position information, so don't even try to find it.
347+ continue
348+ }
349+ spn , found , err := s .matchErrorToModule (ctx , pm , msg )
350+ if err != nil {
351+ event .Error (ctx , "matching error to module" , err )
352+ continue
353+ }
354+ le := locatedErr {
355+ spn : spn ,
356+ msg : msg ,
357+ }
358+ if found {
359+ diagLocations [pm ] = le
360+ } else {
361+ backupDiagLocations [pm ] = le
362+ }
330363 }
331364 }
332365
@@ -336,14 +369,15 @@ func (s *snapshot) extractGoCommandErrors(ctx context.Context, goCmdError string
336369 }
337370
338371 var srcErrs []* source.Diagnostic
339- for pm , spn := range diagLocations {
340- diag , err := s .goCommandDiagnostic (pm , spn , goCmdError )
372+ for pm , le := range diagLocations {
373+ diag , err := s .goCommandDiagnostic (pm , le . spn , le . msg )
341374 if err != nil {
342- return nil , err
375+ event .Error (ctx , "building go command diagnostic" , err )
376+ continue
343377 }
344378 srcErrs = append (srcErrs , diag )
345379 }
346- return srcErrs , nil
380+ return srcErrs
347381}
348382
349383var moduleVersionInErrorRe = regexp .MustCompile (`[:\s]([+-._~0-9A-Za-z]+)@([+-._~0-9A-Za-z]+)[:\s]` )
0 commit comments