internal/lsp: display current diagnostics in the debug server

The change displays outstanding diagnostics on the Client page of
the debug server.

Very occasionally gopls displays incorrect diagnostics or diagnositics
that won't go away.  It is possible that providing more complete
information will help us find the causes, at least when the debug
server is running.

Change-Id: I01f2bbbfeac86e7296f57f4a9aad8e1e658babfa
Reviewed-on: https://go-review.googlesource.com/c/tools/+/285252
Run-TryBot: Peter Weinberger <pjw@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Peter Weinberger <pjw@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
pjw 2021-01-21 08:39:47 -05:00 committed by Peter Weinberger
parent cf1022a4b0
commit e13398c87d
3 changed files with 83 additions and 0 deletions

View File

@ -181,6 +181,7 @@ type Client struct {
Logfile string
GoplsPath string
ServerID string
Service protocol.Server
}
// A Server is an outgoing connection to a remote LSP server.
@ -314,6 +315,16 @@ func (i *Instance) getInfo(r *http.Request) interface{} {
return template.HTML(buf.String())
}
func (i *Instance) AddService(s protocol.Server, session *cache.Session) {
for _, c := range i.State.clients {
if c.Session == session {
c.Service = s
return
}
}
stdlog.Printf("unable to find a Client to add the protocol.Server to")
}
func getMemory(r *http.Request) interface{} {
var m runtime.MemStats
runtime.ReadMemStats(&m)
@ -785,6 +796,29 @@ Using session: <b>{{template "sessionlink" .Session.ID}}</b><br>
{{if .DebugAddress}}Debug this client at: <a href="http://{{localAddress .DebugAddress}}">{{localAddress .DebugAddress}}</a><br>{{end}}
Logfile: {{.Logfile}}<br>
Gopls Path: {{.GoplsPath}}<br>
<h2>Diagnostics</h2>
{{/*Service: []protocol.Server; each server has map[uri]fileReports;
each fileReport: map[diagnosticSoure]diagnosticReport
diagnosticSource is one of 5 source
diagnosticReport: snapshotID and map[hash]*source.Diagnostic
sourceDiagnostic: struct {
Range protocol.Range
Message string
Source string
Code string
CodeHref string
Severity protocol.DiagnosticSeverity
Tags []protocol.DiagnosticTag
Related []RelatedInformation
}
RelatedInformation: struct {
URI span.URI
Range protocol.Range
Message string
}
*/}}
<ul>{{range $k, $v := .Service.Diagnostics}}<li>{{$k}}:<ol>{{range $v}}<li>{{.}}</li>{{end}}</ol></li>{{end}}</ul>
{{end}}
`))

View File

@ -50,6 +50,23 @@ type fileReports struct {
reports map[diagnosticSource]diagnosticReport
}
func (d diagnosticSource) String() string {
switch d {
case modSource:
return "FromSource"
case gcDetailsSource:
return "FromGCDetails"
case analysisSource:
return "FromAnalysis"
case typeCheckSource:
return "FromTypeChecking"
case orphanedSource:
return "FromOrphans"
default:
return fmt.Sprintf("From?%d?", d)
}
}
// hashDiagnostics computes a hash to identify diags.
func hashDiagnostics(diags ...*source.Diagnostic) string {
source.SortDiagnostics(diags)
@ -546,3 +563,34 @@ func (s *Server) shouldIgnoreError(ctx context.Context, snapshot source.Snapshot
})
return !hasGo
}
// Diagnostics formattedfor the debug server
// (all the relevant fields of Server are private)
// (The alternative is to export them)
func (s *Server) Diagnostics() map[string][]string {
ans := make(map[string][]string)
s.diagnosticsMu.Lock()
defer s.diagnosticsMu.Unlock()
for k, v := range s.diagnostics {
fn := k.Filename()
for typ, d := range v.reports {
if len(d.diags) == 0 {
continue
}
for _, dx := range d.diags {
ans[fn] = append(ans[fn], auxStr(dx, d, typ))
}
}
}
return ans
}
func auxStr(v *source.Diagnostic, d diagnosticReport, typ diagnosticSource) string {
// Tags? RelatedInformation?
msg := fmt.Sprintf("(%s)%q(source:%q,code:%q,severity:%s,snapshot:%d,type:%s)",
v.Range, v.Message, v.Source, v.Code, v.Severity, d.snapshotID, typ)
for _, r := range v.Related {
msg += fmt.Sprintf(" [%s:%s,%q]", r.URI.Filename(), r.Range, r.Message)
}
return msg
}

View File

@ -61,6 +61,7 @@ func (s *StreamServer) ServeStream(ctx context.Context, conn jsonrpc2.Conn) erro
server := s.serverForTest
if server == nil {
server = lsp.NewServer(session, client)
debug.GetInstance(ctx).AddService(server, session)
}
// Clients may or may not send a shutdown message. Make sure the server is
// shut down.