forked from sourcegraph/go-langserver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
diagnostics.go
88 lines (82 loc) · 2.1 KB
/
diagnostics.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package langserver
import (
"context"
"fmt"
"go/scanner"
"go/token"
"go/types"
"strings"
"golang.org/x/tools/go/loader"
"github.com/sourcegraph/go-langserver/pkg/lsp"
)
type diagnostics map[string][]*lsp.Diagnostic // map of URI to diagnostics (for PublishDiagnosticParams)
// publishDiagnostics sends diagnostic information (such as compile
// errors) to the client.
func (h *LangHandler) publishDiagnostics(ctx context.Context, conn JSONRPC2Conn, diags diagnostics) error {
for filename, diags := range diags {
params := lsp.PublishDiagnosticsParams{
URI: "file://" + filename,
Diagnostics: make([]lsp.Diagnostic, len(diags)),
}
for i, d := range diags {
params.Diagnostics[i] = *d
}
if err := conn.Notify(ctx, "textDocument/publishDiagnostics", params); err != nil {
return err
}
}
return nil
}
func errsToDiagnostics(typeErrs []error, prog *loader.Program) (diagnostics, error) {
var diags diagnostics
for _, typeErr := range typeErrs {
var (
p token.Position
pEnd token.Position
msg string
)
switch e := typeErr.(type) {
case types.Error:
p = e.Fset.Position(e.Pos)
_, path, _ := prog.PathEnclosingInterval(e.Pos, e.Pos)
if len(path) > 0 {
pEnd = e.Fset.Position(path[0].End())
}
msg = e.Msg
case scanner.Error:
p = e.Pos
msg = e.Msg
case scanner.ErrorList:
if len(e) == 0 {
continue
}
p = e[0].Pos
msg = e[0].Msg
if len(e) > 1 {
msg = fmt.Sprintf("%s (and %d more errors)", msg, len(e)-1)
}
default:
return nil, fmt.Errorf("unexpected type error: %#+v", typeErr)
}
// LSP is 0-indexed, so subtract one from the numbers Go reports.
start := lsp.Position{Line: p.Line - 1, Character: p.Column - 1}
end := lsp.Position{Line: pEnd.Line - 1, Character: pEnd.Column - 1}
if !pEnd.IsValid() {
end = start
}
diag := &lsp.Diagnostic{
Range: lsp.Range{
Start: start,
End: end,
},
Severity: lsp.Error,
Source: "go",
Message: strings.TrimSpace(msg),
}
if diags == nil {
diags = diagnostics{}
}
diags[p.Filename] = append(diags[p.Filename], diag)
}
return diags, nil
}