go/analysis: add Analyser.URL and Diagnostic.URI fields
These fields allow the analyzer to provide links to
its online documentation.
Also:
- set URI field for all x/tools Analyzers.
- include these URIs in the gopls docs.
Fixes golang/go#57906
Change-Id: Iec0a34386d834edfae4e9161a18a1d14a7a43b74
Reviewed-on: https://go-review.googlesource.com/c/tools/+/476615
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Alan Donovan <adonovan@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/go/analysis/analysis.go b/go/analysis/analysis.go
index 44ada22..bc237ac 100644
--- a/go/analysis/analysis.go
+++ b/go/analysis/analysis.go
@@ -24,6 +24,10 @@
// (no capital or period, max ~60 letters).
Doc string
+ // URL holds an optional link to a web page with additional
+ // documentation for this analyzer.
+ URL string
+
// Flags defines any flags accepted by the analyzer.
// The manner in which these flags are exposed to the user
// depends on the driver which runs the analyzer.
diff --git a/go/analysis/diagnostic.go b/go/analysis/diagnostic.go
index 5cdcf46..7646ad0 100644
--- a/go/analysis/diagnostic.go
+++ b/go/analysis/diagnostic.go
@@ -20,6 +20,17 @@
Category string // optional
Message string
+ // URL is the optional location of a web page that provides
+ // additional documentation for this diagnostic.
+ //
+ // If URL is empty but a Category is specified, then the
+ // Analysis driver should treat the URL as "#"+Category.
+ //
+ // The URL may be relative. If so, the base URL is that of the
+ // Analyzer that produced the diagnostic;
+ // see https://pkg.go.dev/net/url#URL.ResolveReference.
+ URL string
+
// SuggestedFixes contains suggested fixes for a diagnostic which can be used to perform
// edits to a file that address the diagnostic.
// TODO(matloob): Should multiple SuggestedFixes be allowed for a diagnostic?
diff --git a/go/analysis/passes/asmdecl/asmdecl.go b/go/analysis/passes/asmdecl/asmdecl.go
index 7288559..e24dac9 100644
--- a/go/analysis/passes/asmdecl/asmdecl.go
+++ b/go/analysis/passes/asmdecl/asmdecl.go
@@ -27,6 +27,7 @@
var Analyzer = &analysis.Analyzer{
Name: "asmdecl",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/asmdecl",
Run: run,
}
diff --git a/go/analysis/passes/assign/assign.go b/go/analysis/passes/assign/assign.go
index 89146b7..b84b79c 100644
--- a/go/analysis/passes/assign/assign.go
+++ b/go/analysis/passes/assign/assign.go
@@ -30,6 +30,7 @@
var Analyzer = &analysis.Analyzer{
Name: "assign",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/atomic/atomic.go b/go/analysis/passes/atomic/atomic.go
index 9261db7..1e980c6 100644
--- a/go/analysis/passes/atomic/atomic.go
+++ b/go/analysis/passes/atomic/atomic.go
@@ -28,6 +28,7 @@
var Analyzer = &analysis.Analyzer{
Name: "atomic",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
diff --git a/go/analysis/passes/atomicalign/atomicalign.go b/go/analysis/passes/atomicalign/atomicalign.go
index e2e1a4f..fc2ce30 100644
--- a/go/analysis/passes/atomicalign/atomicalign.go
+++ b/go/analysis/passes/atomicalign/atomicalign.go
@@ -25,6 +25,7 @@
var Analyzer = &analysis.Analyzer{
Name: "atomicalign",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomicalign",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/bools/bools.go b/go/analysis/passes/bools/bools.go
index 0d8b0bf..4219f08 100644
--- a/go/analysis/passes/bools/bools.go
+++ b/go/analysis/passes/bools/bools.go
@@ -22,6 +22,7 @@
var Analyzer = &analysis.Analyzer{
Name: "bools",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/bools",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/buildssa/buildssa.go b/go/analysis/passes/buildssa/buildssa.go
index 02b7b18..ad42f39 100644
--- a/go/analysis/passes/buildssa/buildssa.go
+++ b/go/analysis/passes/buildssa/buildssa.go
@@ -22,6 +22,7 @@
var Analyzer = &analysis.Analyzer{
Name: "buildssa",
Doc: "build SSA-form IR for later passes",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildssa",
Run: run,
ResultType: reflect.TypeOf(new(SSA)),
}
diff --git a/go/analysis/passes/buildtag/buildtag.go b/go/analysis/passes/buildtag/buildtag.go
index 775e507..a2a4a89 100644
--- a/go/analysis/passes/buildtag/buildtag.go
+++ b/go/analysis/passes/buildtag/buildtag.go
@@ -25,6 +25,7 @@
var Analyzer = &analysis.Analyzer{
Name: "buildtag",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildtag",
Run: runBuildTag,
}
diff --git a/go/analysis/passes/cgocall/cgocall.go b/go/analysis/passes/cgocall/cgocall.go
index b61ee5c..afff0d8 100644
--- a/go/analysis/passes/cgocall/cgocall.go
+++ b/go/analysis/passes/cgocall/cgocall.go
@@ -35,6 +35,7 @@
var Analyzer = &analysis.Analyzer{
Name: "cgocall",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/cgocall",
RunDespiteErrors: true,
Run: run,
}
diff --git a/go/analysis/passes/composite/composite.go b/go/analysis/passes/composite/composite.go
index 64e184d..20fb708 100644
--- a/go/analysis/passes/composite/composite.go
+++ b/go/analysis/passes/composite/composite.go
@@ -37,6 +37,7 @@
var Analyzer = &analysis.Analyzer{
Name: "composites",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composites",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
diff --git a/go/analysis/passes/copylock/copylock.go b/go/analysis/passes/copylock/copylock.go
index 8cc93e9..b3ca8ad 100644
--- a/go/analysis/passes/copylock/copylock.go
+++ b/go/analysis/passes/copylock/copylock.go
@@ -29,6 +29,7 @@
var Analyzer = &analysis.Analyzer{
Name: "copylocks",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/copylocks",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
diff --git a/go/analysis/passes/ctrlflow/ctrlflow.go b/go/analysis/passes/ctrlflow/ctrlflow.go
index 73746d6..d21adee 100644
--- a/go/analysis/passes/ctrlflow/ctrlflow.go
+++ b/go/analysis/passes/ctrlflow/ctrlflow.go
@@ -24,6 +24,7 @@
var Analyzer = &analysis.Analyzer{
Name: "ctrlflow",
Doc: "build a control-flow graph",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ctrlflow",
Run: run,
ResultType: reflect.TypeOf(new(CFGs)),
FactTypes: []analysis.Fact{new(noReturn)},
diff --git a/go/analysis/passes/deepequalerrors/deepequalerrors.go b/go/analysis/passes/deepequalerrors/deepequalerrors.go
index 9ea1373..afc4fdc 100644
--- a/go/analysis/passes/deepequalerrors/deepequalerrors.go
+++ b/go/analysis/passes/deepequalerrors/deepequalerrors.go
@@ -28,6 +28,7 @@
var Analyzer = &analysis.Analyzer{
Name: "deepequalerrors",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/deepequalerrors",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/directive/directive.go b/go/analysis/passes/directive/directive.go
index 76d852c..1146d7b 100644
--- a/go/analysis/passes/directive/directive.go
+++ b/go/analysis/passes/directive/directive.go
@@ -36,6 +36,7 @@
var Analyzer = &analysis.Analyzer{
Name: "directive",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/directive",
Run: runDirective,
}
diff --git a/go/analysis/passes/errorsas/errorsas.go b/go/analysis/passes/errorsas/errorsas.go
index 96adad3..867fc26 100644
--- a/go/analysis/passes/errorsas/errorsas.go
+++ b/go/analysis/passes/errorsas/errorsas.go
@@ -25,6 +25,7 @@
var Analyzer = &analysis.Analyzer{
Name: "errorsas",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/fieldalignment/fieldalignment.go b/go/analysis/passes/fieldalignment/fieldalignment.go
index aff6630..012e2ec 100644
--- a/go/analysis/passes/fieldalignment/fieldalignment.go
+++ b/go/analysis/passes/fieldalignment/fieldalignment.go
@@ -51,6 +51,7 @@
var Analyzer = &analysis.Analyzer{
Name: "fieldalignment",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/findcall/findcall.go b/go/analysis/passes/findcall/findcall.go
index 27b1b84..2671573 100644
--- a/go/analysis/passes/findcall/findcall.go
+++ b/go/analysis/passes/findcall/findcall.go
@@ -26,6 +26,7 @@
var Analyzer = &analysis.Analyzer{
Name: "findcall",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/findcall",
Run: run,
RunDespiteErrors: true,
FactTypes: []analysis.Fact{new(foundFact)},
diff --git a/go/analysis/passes/framepointer/framepointer.go b/go/analysis/passes/framepointer/framepointer.go
index 741492e..0b3ded4 100644
--- a/go/analysis/passes/framepointer/framepointer.go
+++ b/go/analysis/passes/framepointer/framepointer.go
@@ -20,6 +20,7 @@
var Analyzer = &analysis.Analyzer{
Name: "framepointer",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/framepointer",
Run: run,
}
diff --git a/go/analysis/passes/httpresponse/httpresponse.go b/go/analysis/passes/httpresponse/httpresponse.go
index 3b9168c..61c3b76 100644
--- a/go/analysis/passes/httpresponse/httpresponse.go
+++ b/go/analysis/passes/httpresponse/httpresponse.go
@@ -35,6 +35,7 @@
var Analyzer = &analysis.Analyzer{
Name: "httpresponse",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/httpresponse",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/ifaceassert/ifaceassert.go b/go/analysis/passes/ifaceassert/ifaceassert.go
index 30130f6..b01db37 100644
--- a/go/analysis/passes/ifaceassert/ifaceassert.go
+++ b/go/analysis/passes/ifaceassert/ifaceassert.go
@@ -34,6 +34,7 @@
var Analyzer = &analysis.Analyzer{
Name: "ifaceassert",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/inspect/inspect.go b/go/analysis/passes/inspect/inspect.go
index 165c70c..3b121cb 100644
--- a/go/analysis/passes/inspect/inspect.go
+++ b/go/analysis/passes/inspect/inspect.go
@@ -38,6 +38,7 @@
var Analyzer = &analysis.Analyzer{
Name: "inspect",
Doc: "optimize AST traversal for later passes",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inspect",
Run: run,
RunDespiteErrors: true,
ResultType: reflect.TypeOf(new(inspector.Inspector)),
diff --git a/go/analysis/passes/loopclosure/loopclosure.go b/go/analysis/passes/loopclosure/loopclosure.go
index ae5b415..5a310bf 100644
--- a/go/analysis/passes/loopclosure/loopclosure.go
+++ b/go/analysis/passes/loopclosure/loopclosure.go
@@ -78,6 +78,7 @@
var Analyzer = &analysis.Analyzer{
Name: "loopclosure",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/lostcancel/lostcancel.go b/go/analysis/passes/lostcancel/lostcancel.go
index de6f840..29fa65b 100644
--- a/go/analysis/passes/lostcancel/lostcancel.go
+++ b/go/analysis/passes/lostcancel/lostcancel.go
@@ -28,6 +28,7 @@
var Analyzer = &analysis.Analyzer{
Name: "lostcancel",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
Run: run,
Requires: []*analysis.Analyzer{
inspect.Analyzer,
diff --git a/go/analysis/passes/nilfunc/nilfunc.go b/go/analysis/passes/nilfunc/nilfunc.go
index e4c66df..a7ec177 100644
--- a/go/analysis/passes/nilfunc/nilfunc.go
+++ b/go/analysis/passes/nilfunc/nilfunc.go
@@ -24,6 +24,7 @@
var Analyzer = &analysis.Analyzer{
Name: "nilfunc",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/nilness/nilness.go b/go/analysis/passes/nilness/nilness.go
index 6849c33..e504945 100644
--- a/go/analysis/passes/nilness/nilness.go
+++ b/go/analysis/passes/nilness/nilness.go
@@ -57,6 +57,7 @@
var Analyzer = &analysis.Analyzer{
Name: "nilness",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness",
Run: run,
Requires: []*analysis.Analyzer{buildssa.Analyzer},
}
diff --git a/go/analysis/passes/pkgfact/pkgfact.go b/go/analysis/passes/pkgfact/pkgfact.go
index f4f5616..4bf33d4 100644
--- a/go/analysis/passes/pkgfact/pkgfact.go
+++ b/go/analysis/passes/pkgfact/pkgfact.go
@@ -38,6 +38,7 @@
var Analyzer = &analysis.Analyzer{
Name: "pkgfact",
Doc: "gather name/value pairs from constant declarations",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/pkgfact",
Run: run,
FactTypes: []analysis.Fact{new(pairsFact)},
ResultType: reflect.TypeOf(map[string]string{}),
diff --git a/go/analysis/passes/printf/printf.go b/go/analysis/passes/printf/printf.go
index daaf709..008c4d7 100644
--- a/go/analysis/passes/printf/printf.go
+++ b/go/analysis/passes/printf/printf.go
@@ -35,6 +35,7 @@
var Analyzer = &analysis.Analyzer{
Name: "printf",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
ResultType: reflect.TypeOf((*Result)(nil)),
diff --git a/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go b/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
index ef21f0e..1ae8ea5 100644
--- a/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
+++ b/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
@@ -39,6 +39,7 @@
var Analyzer = &analysis.Analyzer{
Name: "reflectvaluecompare",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/reflectvaluecompare",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/shadow/shadow.go b/go/analysis/passes/shadow/shadow.go
index a19cecd..c2836ee 100644
--- a/go/analysis/passes/shadow/shadow.go
+++ b/go/analysis/passes/shadow/shadow.go
@@ -46,6 +46,7 @@
var Analyzer = &analysis.Analyzer{
Name: "shadow",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shadow",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/shift/shift.go b/go/analysis/passes/shift/shift.go
index e968f27..bafb911 100644
--- a/go/analysis/passes/shift/shift.go
+++ b/go/analysis/passes/shift/shift.go
@@ -29,6 +29,7 @@
var Analyzer = &analysis.Analyzer{
Name: "shift",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shift",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/sigchanyzer/sigchanyzer.go b/go/analysis/passes/sigchanyzer/sigchanyzer.go
index c490a84..5921b70 100644
--- a/go/analysis/passes/sigchanyzer/sigchanyzer.go
+++ b/go/analysis/passes/sigchanyzer/sigchanyzer.go
@@ -27,6 +27,7 @@
var Analyzer = &analysis.Analyzer{
Name: "sigchanyzer",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sigchanyzer",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/sortslice/analyzer.go b/go/analysis/passes/sortslice/analyzer.go
index f85837d..eecb3b8 100644
--- a/go/analysis/passes/sortslice/analyzer.go
+++ b/go/analysis/passes/sortslice/analyzer.go
@@ -27,11 +27,13 @@
var Analyzer = &analysis.Analyzer{
Name: "sortslice",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sortslice",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
func run(pass *analysis.Pass) (interface{}, error) {
+ // TODO(adonovan): opt: first check for import "sort".
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
diff --git a/go/analysis/passes/stdmethods/stdmethods.go b/go/analysis/passes/stdmethods/stdmethods.go
index 41f455d..b948bf7 100644
--- a/go/analysis/passes/stdmethods/stdmethods.go
+++ b/go/analysis/passes/stdmethods/stdmethods.go
@@ -40,6 +40,7 @@
var Analyzer = &analysis.Analyzer{
Name: "stdmethods",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/stringintconv/string.go b/go/analysis/passes/stringintconv/string.go
index e41de80..ed8730e 100644
--- a/go/analysis/passes/stringintconv/string.go
+++ b/go/analysis/passes/stringintconv/string.go
@@ -34,6 +34,7 @@
var Analyzer = &analysis.Analyzer{
Name: "stringintconv",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/structtag/structtag.go b/go/analysis/passes/structtag/structtag.go
index f0b1505..a0beb46 100644
--- a/go/analysis/passes/structtag/structtag.go
+++ b/go/analysis/passes/structtag/structtag.go
@@ -28,6 +28,7 @@
var Analyzer = &analysis.Analyzer{
Name: "structtag",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/structtag",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
diff --git a/go/analysis/passes/testinggoroutine/testinggoroutine.go b/go/analysis/passes/testinggoroutine/testinggoroutine.go
index 7ea8f77..7710dc8 100644
--- a/go/analysis/passes/testinggoroutine/testinggoroutine.go
+++ b/go/analysis/passes/testinggoroutine/testinggoroutine.go
@@ -31,6 +31,7 @@
var Analyzer = &analysis.Analyzer{
Name: "testinggoroutine",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/tests/tests.go b/go/analysis/passes/tests/tests.go
index 935aad0..fd2e055 100644
--- a/go/analysis/passes/tests/tests.go
+++ b/go/analysis/passes/tests/tests.go
@@ -33,6 +33,7 @@
var Analyzer = &analysis.Analyzer{
Name: "tests",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
Run: run,
}
diff --git a/go/analysis/passes/timeformat/timeformat.go b/go/analysis/passes/timeformat/timeformat.go
index acb198f..7ada017 100644
--- a/go/analysis/passes/timeformat/timeformat.go
+++ b/go/analysis/passes/timeformat/timeformat.go
@@ -32,6 +32,7 @@
var Analyzer = &analysis.Analyzer{
Name: "timeformat",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/unmarshal/unmarshal.go b/go/analysis/passes/unmarshal/unmarshal.go
index 5129048..932229e 100644
--- a/go/analysis/passes/unmarshal/unmarshal.go
+++ b/go/analysis/passes/unmarshal/unmarshal.go
@@ -25,6 +25,7 @@
var Analyzer = &analysis.Analyzer{
Name: "unmarshal",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/unreachable/unreachable.go b/go/analysis/passes/unreachable/unreachable.go
index 90896dd..bf877f4 100644
--- a/go/analysis/passes/unreachable/unreachable.go
+++ b/go/analysis/passes/unreachable/unreachable.go
@@ -26,6 +26,7 @@
var Analyzer = &analysis.Analyzer{
Name: "unreachable",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
diff --git a/go/analysis/passes/unsafeptr/unsafeptr.go b/go/analysis/passes/unsafeptr/unsafeptr.go
index ed86e5e..cf4cdd5 100644
--- a/go/analysis/passes/unsafeptr/unsafeptr.go
+++ b/go/analysis/passes/unsafeptr/unsafeptr.go
@@ -28,6 +28,7 @@
var Analyzer = &analysis.Analyzer{
Name: "unsafeptr",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/unusedresult/unusedresult.go b/go/analysis/passes/unusedresult/unusedresult.go
index 06747ba..e85b7c3 100644
--- a/go/analysis/passes/unusedresult/unusedresult.go
+++ b/go/analysis/passes/unusedresult/unusedresult.go
@@ -35,6 +35,7 @@
var Analyzer = &analysis.Analyzer{
Name: "unusedresult",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/unusedwrite/unusedwrite.go b/go/analysis/passes/unusedwrite/unusedwrite.go
index 9cc45e0..478c774 100644
--- a/go/analysis/passes/unusedwrite/unusedwrite.go
+++ b/go/analysis/passes/unusedwrite/unusedwrite.go
@@ -45,6 +45,7 @@
var Analyzer = &analysis.Analyzer{
Name: "unusedwrite",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedwrite",
Requires: []*analysis.Analyzer{buildssa.Analyzer},
Run: run,
}
diff --git a/go/analysis/passes/usesgenerics/usesgenerics.go b/go/analysis/passes/usesgenerics/usesgenerics.go
index 4956e0e..63eb723 100644
--- a/go/analysis/passes/usesgenerics/usesgenerics.go
+++ b/go/analysis/passes/usesgenerics/usesgenerics.go
@@ -18,6 +18,7 @@
var Analyzer = &analysis.Analyzer{
Name: "usesgenerics",
Doc: Doc,
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/usesgenerics",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
ResultType: reflect.TypeOf((*Result)(nil)),
diff --git a/gopls/doc/generate.go b/gopls/doc/generate.go
index d674bfc..332faeb 100644
--- a/gopls/doc/generate.go
+++ b/gopls/doc/generate.go
@@ -516,6 +516,7 @@
json = append(json, &source.AnalyzerJSON{
Name: a.Analyzer.Name,
Doc: a.Analyzer.Doc,
+ URL: a.Analyzer.URL,
Default: a.Enabled,
})
}
diff --git a/gopls/internal/lsp/cache/analysis.go b/gopls/internal/lsp/cache/analysis.go
index bd0c79a..5d8616b 100644
--- a/gopls/internal/lsp/cache/analysis.go
+++ b/gopls/internal/lsp/cache/analysis.go
@@ -1232,7 +1232,7 @@
// Severity for analysis diagnostics is dynamic, based on user
// configuration per analyzer.
// Code and CodeHref are unset for Analysis diagnostics,
- // TODO(rfindley): set Code fields if/when golang/go#57906 is accepted.
+ // TODO(rfindley): derive Code fields from diag.URL.
Source: diag.Category,
Message: diag.Message,
SuggestedFixes: fixes,
diff --git a/gopls/internal/lsp/source/api_json.go b/gopls/internal/lsp/source/api_json.go
index 74d8d71..5b0f226 100644
--- a/gopls/internal/lsp/source/api_json.go
+++ b/gopls/internal/lsp/source/api_json.go
@@ -854,56 +854,67 @@
{
Name: "asmdecl",
Doc: "report mismatches between assembly files and Go declarations",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/asmdecl",
Default: true,
},
{
Name: "assign",
Doc: "check for useless assignments\n\nThis checker reports assignments of the form x = x or a[i] = a[i].\nThese are almost always useless, and even when they aren't they are\nusually a mistake.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
Default: true,
},
{
Name: "atomic",
Doc: "check for common mistakes using the sync/atomic package\n\nThe atomic checker looks for assignment statements of the form:\n\n\tx = atomic.AddUint64(&x, 1)\n\nwhich are not atomic.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
Default: true,
},
{
Name: "atomicalign",
Doc: "check for non-64-bits-aligned arguments to sync/atomic functions",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomicalign",
Default: true,
},
{
Name: "bools",
Doc: "check for common mistakes involving boolean operators",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/bools",
Default: true,
},
{
Name: "buildtag",
Doc: "check //go:build and // +build directives",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildtag",
Default: true,
},
{
Name: "cgocall",
Doc: "detect some violations of the cgo pointer passing rules\n\nCheck for invalid cgo pointer passing.\nThis looks for code that uses cgo to call C code passing values\nwhose types are almost always invalid according to the cgo pointer\nsharing rules.\nSpecifically, it warns about attempts to pass a Go chan, map, func,\nor slice to C, either directly, or via a pointer, array, or struct.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/cgocall",
Default: true,
},
{
Name: "composites",
Doc: "check for unkeyed composite literals\n\nThis analyzer reports a diagnostic for composite literals of struct\ntypes imported from another package that do not use the field-keyed\nsyntax. Such literals are fragile because the addition of a new field\n(even if unexported) to the struct will cause compilation to fail.\n\nAs an example,\n\n\terr = &net.DNSConfigError{err}\n\nshould be replaced by:\n\n\terr = &net.DNSConfigError{Err: err}\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composites",
Default: true,
},
{
Name: "copylocks",
Doc: "check for locks erroneously passed by value\n\nInadvertently copying a value containing a lock, such as sync.Mutex or\nsync.WaitGroup, may cause both copies to malfunction. Generally such\nvalues should be referred to through a pointer.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/copylocks",
Default: true,
},
{
Name: "deepequalerrors",
Doc: "check for calls of reflect.DeepEqual on error values\n\nThe deepequalerrors checker looks for calls of the form:\n\n reflect.DeepEqual(err1, err2)\n\nwhere err1 and err2 are errors. Using reflect.DeepEqual to compare\nerrors is discouraged.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/deepequalerrors",
Default: true,
},
{
Name: "directive",
Doc: "check Go toolchain directives such as //go:debug\n\nThis analyzer checks for problems with known Go toolchain directives\nin all Go source files in a package directory, even those excluded by\n//go:build constraints, and all non-Go source files too.\n\nFor //go:debug (see https://go.dev/doc/godebug), the analyzer checks\nthat the directives are placed only in Go source files, only above the\npackage comment, and only in package main or *_test.go files.\n\nSupport for other known directives may be added in the future.\n\nThis analyzer does not check //go:build, which is handled by the\nbuildtag analyzer.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/directive",
Default: true,
},
{
@@ -914,20 +925,24 @@
{
Name: "errorsas",
Doc: "report passing non-pointer or non-error values to errors.As\n\nThe errorsas analysis reports calls to errors.As where the type\nof the second argument is not a pointer to a type implementing error.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas",
Default: true,
},
{
Name: "fieldalignment",
Doc: "find structs that would use less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to use less memory, and provides\na suggested edit with the most compact order.\n\nNote that there are two different diagnostics reported. One checks struct size,\nand the other reports \"pointer bytes\" used. Pointer bytes is how many bytes of the\nobject that the garbage collector has to potentially scan for pointers, for example:\n\n\tstruct { uint32; string }\n\nhave 16 pointer bytes because the garbage collector has to scan up through the string's\ninner pointer.\n\n\tstruct { string; *uint32 }\n\nhas 24 pointer bytes because it has to scan further through the *uint32.\n\n\tstruct { string; uint32 }\n\nhas 8 because it can stop immediately after the string pointer.\n\nBe aware that the most compact order is not always the most efficient.\nIn rare cases it may cause two variables each updated by its own goroutine\nto occupy the same CPU cache line, inducing a form of memory contention\nknown as \"false sharing\" that slows down both goroutines.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment",
},
{
Name: "httpresponse",
Doc: "check for mistakes using HTTP responses\n\nA common mistake when using the net/http package is to defer a function\ncall to close the http.Response Body before checking the error that\ndetermines whether the response is valid:\n\n\tresp, err := http.Head(url)\n\tdefer resp.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// (defer statement belongs here)\n\nThis checker helps uncover latent nil dereference bugs by reporting a\ndiagnostic for such mistakes.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/httpresponse",
Default: true,
},
{
Name: "ifaceassert",
Doc: "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
Default: true,
},
{
@@ -938,34 +953,41 @@
{
Name: "loopclosure",
Doc: "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n for _, v := range list {\n defer func() {\n use(v) // incorrect\n }()\n }\n\nOne fix is to create a new variable for each iteration of the loop:\n\n for _, v := range list {\n v := v // new var per iteration\n defer func() {\n use(v) // ok\n }()\n }\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n for _, v := range elem {\n go func() {\n use(v) // incorrect, and a data race\n }()\n }\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n func Test(t *testing.T) {\n for _, test := range tests {\n t.Run(test.name, func(t *testing.T) {\n t.Parallel()\n use(test) // incorrect, and a data race\n })\n }\n }\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
Default: true,
},
{
Name: "lostcancel",
Doc: "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
Default: true,
},
{
Name: "nilfunc",
Doc: "check for useless comparisons between functions and nil\n\nA useless comparison is one like f == nil as opposed to f() == nil.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
Default: true,
},
{
Name: "nilness",
Doc: "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness",
},
{
Name: "printf",
Doc: "check consistency of Printf format strings and arguments\n\nThe check applies to known functions (for example, those in package fmt)\nas well as any detected wrappers of known functions.\n\nA function that wants to avail itself of printf checking but is not\nfound by this analyzer's heuristics (for example, due to use of\ndynamic calls) can insert a bogus call:\n\n\tif false {\n\t\t_ = fmt.Sprintf(format, args...) // enable printf checking\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
Default: true,
},
{
Name: "shadow",
Doc: "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shadow",
},
{
Name: "shift",
Doc: "check for shifts that equal or exceed the width of the integer",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shift",
Default: true,
},
{
@@ -986,51 +1008,61 @@
{
Name: "sortslice",
Doc: "check the argument type of sort.Slice\n\nsort.Slice requires an argument of a slice type. Check that\nthe interface{} value passed to sort.Slice is actually a slice.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sortslice",
Default: true,
},
{
Name: "stdmethods",
Doc: "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n func (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
Default: true,
},
{
Name: "stringintconv",
Doc: "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
Default: true,
},
{
Name: "structtag",
Doc: "check that struct field tags conform to reflect.StructTag.Get\n\nAlso report certain struct tags (json, xml) used with unexported fields.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/structtag",
Default: true,
},
{
Name: "testinggoroutine",
Doc: "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n go func() {\n t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n }()\n}\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
Default: true,
},
{
Name: "tests",
Doc: "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
Default: true,
},
{
Name: "timeformat",
Doc: "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat",
Default: true,
},
{
Name: "unmarshal",
Doc: "report passing non-pointer or non-interface values to unmarshal\n\nThe unmarshal analysis reports calls to functions such as json.Unmarshal\nin which the argument type is not a pointer or an interface.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
Default: true,
},
{
Name: "unreachable",
Doc: "check for unreachable code\n\nThe unreachable analyzer finds statements that execution can never reach\nbecause they are preceded by an return statement, a call to panic, an\ninfinite loop, or similar constructs.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
Default: true,
},
{
Name: "unsafeptr",
Doc: "check for invalid conversions of uintptr to unsafe.Pointer\n\nThe unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer\nto convert integers to pointers. A conversion from uintptr to\nunsafe.Pointer is invalid if it implies that there is a uintptr-typed\nword in memory that holds a pointer value, because that word will be\ninvisible to stack copying and to the garbage collector.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
Default: true,
},
{
@@ -1040,11 +1072,13 @@
{
Name: "unusedresult",
Doc: "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side effects,\nso it is always a mistake to discard the result. This analyzer reports\ncalls to certain functions in which the result of the call is ignored.\n\nThe set of functions may be controlled using flags.",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
Default: true,
},
{
Name: "unusedwrite",
Doc: "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input { // v is a copy\n\t\t\tv.x = i // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() { // t is a copy\n\t\tt.x = i // unused write to field x\n\t}\n",
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedwrite",
},
{
Name: "useany",
diff --git a/gopls/internal/lsp/source/options.go b/gopls/internal/lsp/source/options.go
index e4cfb6d5..3357495 100644
--- a/gopls/internal/lsp/source/options.go
+++ b/gopls/internal/lsp/source/options.go
@@ -1605,6 +1605,7 @@
type AnalyzerJSON struct {
Name string
Doc string
+ URL string
Default bool
}
diff --git a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go
index 71187a9..e884695 100644
--- a/gopls/internal/lsp/source/view.go
+++ b/gopls/internal/lsp/source/view.go
@@ -819,7 +819,7 @@
// An Diagnostic corresponds to an LSP Diagnostic.
// https://microsoft.github.io/language-server-protocol/specification#diagnostic
type Diagnostic struct {
- URI span.URI
+ URI span.URI // of diagnosed file (not diagnostic documentation)
Range protocol.Range
Severity protocol.DiagnosticSeverity
Code string