blob: 1a38d734d9224f93a3437cd26e7db4529a37d2f9 [file] [log] [blame]
package lsp
import (
"go/token"
"strconv"
"strings"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/protocol"
)
func (v *view) diagnostics(uri protocol.DocumentURI) (map[string][]protocol.Diagnostic, error) {
pkg, err := v.typeCheck(uri)
if err != nil {
return nil, err
}
reports := make(map[string][]protocol.Diagnostic)
for _, filename := range pkg.GoFiles {
reports[filename] = []protocol.Diagnostic{}
}
var parseErrors, typeErrors []packages.Error
for _, err := range pkg.Errors {
switch err.Kind {
case packages.ParseError:
parseErrors = append(parseErrors, err)
case packages.TypeError:
typeErrors = append(typeErrors, err)
default:
// ignore other types of errors
continue
}
}
// Don't report type errors if there are parse errors.
errors := typeErrors
if len(parseErrors) > 0 {
errors = parseErrors
}
for _, err := range errors {
pos := parseErrorPos(err)
line := float64(pos.Line) - 1
col := float64(pos.Column) - 1
diagnostic := protocol.Diagnostic{
// TODO(rstambler): Add support for diagnostic ranges.
Range: protocol.Range{
Start: protocol.Position{
Line: line,
Character: col,
},
End: protocol.Position{
Line: line,
Character: col,
},
},
Severity: protocol.SeverityError,
Source: "LSP: Go compiler",
Message: err.Msg,
}
if _, ok := reports[pos.Filename]; ok {
reports[pos.Filename] = append(reports[pos.Filename], diagnostic)
}
}
return reports, nil
}
func parseErrorPos(pkgErr packages.Error) (pos token.Position) {
split := strings.Split(pkgErr.Pos, ":")
if len(split) <= 1 {
return pos
}
pos.Filename = split[0]
line, err := strconv.ParseInt(split[1], 10, 64)
if err != nil {
return pos
}
pos.Line = int(line)
if len(split) == 3 {
col, err := strconv.ParseInt(split[2], 10, 64)
if err != nil {
return pos
}
pos.Column = int(col)
}
return pos
}