gopls: propagate Staticcheck's diagnostic severities

Each analyzer in Staticcheck is annotated with the appropriate
severity to use for its diagnostics. For example, most checks in SA*
produce warnings, but some produce errors (e.g. when passing an
invalid regular expression to regexp.Compile).

This will be especially important for a follow-up CL that enables
Staticcheck's new quickfix category, which contains optional
refactorings that shouldn't be flagged as warnings.

Change-Id: I6235303a3bb188ef79f52952c01e9585301a3270
Reviewed-on: https://go-review.googlesource.com/c/tools/+/322491
Trust: Dominik Honnef <dominik@honnef.co>
Run-TryBot: Dominik Honnef <dominik@honnef.co>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/gopls/internal/hooks/analysis.go b/gopls/internal/hooks/analysis.go
index f9feded..25eed8d 100644
--- a/gopls/internal/hooks/analysis.go
+++ b/gopls/internal/hooks/analysis.go
@@ -8,6 +8,7 @@
 package hooks
 
 import (
+	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
 	"honnef.co/go/tools/analysis/lint"
 	"honnef.co/go/tools/simple"
@@ -16,6 +17,24 @@
 )
 
 func updateAnalyzers(options *source.Options) {
+	mapSeverity := func(severity lint.Severity) protocol.DiagnosticSeverity {
+		switch severity {
+		case lint.SeverityError:
+			return protocol.SeverityError
+		case lint.SeverityDeprecated:
+			// TODO(dh): in LSP, deprecated is a tag, not a severity.
+			//   We'll want to support this once we enable SA5011.
+			return protocol.SeverityWarning
+		case lint.SeverityWarning:
+			return protocol.SeverityWarning
+		case lint.SeverityInfo:
+			return protocol.SeverityInformation
+		case lint.SeverityHint:
+			return protocol.SeverityHint
+		default:
+			return protocol.SeverityWarning
+		}
+	}
 	add := func(analyzers []*lint.Analyzer, skip map[string]struct{}) {
 		for _, a := range analyzers {
 			if _, ok := skip[a.Analyzer.Name]; ok {
@@ -23,7 +42,7 @@
 			}
 
 			enabled := !a.Doc.NonDefault
-			options.AddStaticcheckAnalyzer(a.Analyzer, enabled)
+			options.AddStaticcheckAnalyzer(a.Analyzer, enabled, mapSeverity(a.Doc.Severity))
 		}
 	}
 
diff --git a/internal/lsp/cache/errors.go b/internal/lsp/cache/errors.go
index 42fafae..6cc3e45 100644
--- a/internal/lsp/cache/errors.go
+++ b/internal/lsp/cache/errors.go
@@ -208,10 +208,15 @@
 	if err != nil {
 		return nil, err
 	}
+
+	severity := srcAnalyzer.Severity
+	if severity == 0 {
+		severity = protocol.SeverityWarning
+	}
 	diag := &source.Diagnostic{
 		URI:            spn.URI(),
 		Range:          rng,
-		Severity:       protocol.SeverityWarning,
+		Severity:       severity,
 		Source:         source.AnalyzerErrorKind(e.Category),
 		Message:        e.Message,
 		Related:        related,
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index dfa631e..1f81c9e 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -716,8 +716,12 @@
 	return result
 }
 
-func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer, enabled bool) {
-	o.StaticcheckAnalyzers[a.Name] = &Analyzer{Analyzer: a, Enabled: enabled}
+func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer, enabled bool, severity protocol.DiagnosticSeverity) {
+	o.StaticcheckAnalyzers[a.Name] = &Analyzer{
+		Analyzer: a,
+		Enabled:  enabled,
+		Severity: severity,
+	}
 }
 
 // EnableAllExperiments turns on all of the experimental "off-by-default"
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index 6612d53..a139c50 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -534,6 +534,10 @@
 	// ActionKind is the kind of code action this analyzer produces. If
 	// unspecified the type defaults to quickfix.
 	ActionKind []protocol.CodeActionKind
+
+	// Severity is the severity set for diagnostics reported by this
+	// analyzer. If left unset it defaults to Warning.
+	Severity protocol.DiagnosticSeverity
 }
 
 func (a Analyzer) IsEnabled(view View) bool {