From fe937a7521e50b486d5dcb5802db60e2d1e110d7 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Fri, 31 May 2019 23:31:58 -0400 Subject: [PATCH] internal/lsp: allow fine-grained control over vet checks This change adds an "experimentalDisabledAnalyses" configuration to the "gopls" configuration. A user can specify a list of excluded analyses by analyzer name. Fixes golang/go#31717 Change-Id: I4b162fcd61ecfcef5c926bd0e96f182748a7721d Reviewed-on: https://go-review.googlesource.com/c/tools/+/179920 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot Reviewed-by: Ian Cottrell --- internal/lsp/diagnostics.go | 2 +- internal/lsp/general.go | 9 +++++++++ internal/lsp/lsp_test.go | 2 +- internal/lsp/server.go | 1 + internal/lsp/source/diagnostics.go | 18 ++++++++++++------ internal/lsp/source/source_test.go | 2 +- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go index ffc7c82bab..ba926f41b4 100644 --- a/internal/lsp/diagnostics.go +++ b/internal/lsp/diagnostics.go @@ -28,7 +28,7 @@ func (s *Server) Diagnostics(ctx context.Context, v source.View, uri span.URI) { if !ok { return } - reports, err := source.Diagnostics(ctx, v, gof) + reports, err := source.Diagnostics(ctx, v, gof, s.disabledAnalyses) if err != nil { s.session.Logger().Errorf(ctx, "failed to compute diagnostics for %s: %v", gof.URI(), err) return diff --git a/internal/lsp/general.go b/internal/lsp/general.go index 92e28a5301..c8b6b6b25c 100644 --- a/internal/lsp/general.go +++ b/internal/lsp/general.go @@ -188,6 +188,15 @@ func (s *Server) processConfig(view source.View, config interface{}) error { if noDocsOnHover, ok := c["noDocsOnHover"].(bool); ok { s.noDocsOnHover = noDocsOnHover } + // Check if the user has explicitly disabled any analyses. + if disabledAnalyses, ok := c["experimentalDisabledAnalyses"].([]interface{}); ok { + s.disabledAnalyses = make(map[string]struct{}) + for _, a := range disabledAnalyses { + if a, ok := a.(string); ok { + s.disabledAnalyses[a] = struct{}{} + } + } + } return nil } diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go index a7d12b0f95..6867bfb648 100644 --- a/internal/lsp/lsp_test.go +++ b/internal/lsp/lsp_test.go @@ -68,7 +68,7 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) { if !ok { t.Fatalf("%s is not a Go file: %v", uri, err) } - results, err := source.Diagnostics(context.Background(), v, gof) + results, err := source.Diagnostics(context.Background(), v, gof, nil) if err != nil { t.Fatal(err) } diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 121cc13e83..2903951e96 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -79,6 +79,7 @@ type Server struct { configurationSupported bool dynamicConfigurationSupported bool preferredContentFormat protocol.MarkupKind + disabledAnalyses map[string]struct{} textDocumentSyncKind protocol.TextDocumentSyncKind diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go index 6ae073a0f2..b7b74b7a2a 100644 --- a/internal/lsp/source/diagnostics.go +++ b/internal/lsp/source/diagnostics.go @@ -51,7 +51,7 @@ const ( SeverityError ) -func Diagnostics(ctx context.Context, v View, f GoFile) (map[span.URI][]Diagnostic, error) { +func Diagnostics(ctx context.Context, v View, f GoFile, disabledAnalyses map[string]struct{}) (map[span.URI][]Diagnostic, error) { pkg := f.GetPackage(ctx) if pkg == nil { return singleDiagnostic(f.URI(), "%s is not part of a package", f.URI()), nil @@ -70,7 +70,7 @@ func Diagnostics(ctx context.Context, v View, f GoFile) (map[span.URI][]Diagnost // Run diagnostics for the package that this URI belongs to. if !diagnostics(ctx, v, pkg, reports) { // If we don't have any list, parse, or type errors, run analyses. - if err := analyses(ctx, v, pkg, reports); err != nil { + if err := analyses(ctx, v, pkg, disabledAnalyses, reports); err != nil { v.Session().Logger().Errorf(ctx, "failed to run analyses for %s: %v", f.URI(), err) } } @@ -126,9 +126,9 @@ func diagnostics(ctx context.Context, v View, pkg Package, reports map[span.URI] return len(diags) != 0 } -func analyses(ctx context.Context, v View, pkg Package, reports map[span.URI][]Diagnostic) error { +func analyses(ctx context.Context, v View, pkg Package, disabledAnalyses map[string]struct{}, reports map[span.URI][]Diagnostic) error { // Type checking and parsing succeeded. Run analyses. - if err := runAnalyses(ctx, v, pkg, func(a *analysis.Analyzer, diag analysis.Diagnostic) error { + if err := runAnalyses(ctx, v, pkg, disabledAnalyses, func(a *analysis.Analyzer, diag analysis.Diagnostic) error { r := span.NewRange(v.Session().Cache().FileSet(), diag.Pos, diag.End) s, err := r.Span() if err != nil { @@ -234,9 +234,10 @@ func singleDiagnostic(uri span.URI, format string, a ...interface{}) map[span.UR } } -func runAnalyses(ctx context.Context, v View, pkg Package, report func(a *analysis.Analyzer, diag analysis.Diagnostic) error) error { +func runAnalyses(ctx context.Context, v View, pkg Package, disabledAnalyses map[string]struct{}, report func(a *analysis.Analyzer, diag analysis.Diagnostic) error) error { // The traditional vet suite: - analyzers := []*analysis.Analyzer{ + var analyzers []*analysis.Analyzer + for _, a := range []*analysis.Analyzer{ asmdecl.Analyzer, assign.Analyzer, atomic.Analyzer, @@ -259,6 +260,11 @@ func runAnalyses(ctx context.Context, v View, pkg Package, report func(a *analys unreachable.Analyzer, unsafeptr.Analyzer, unusedresult.Analyzer, + } { + if _, ok := disabledAnalyses[a.Name]; ok { + continue + } + analyzers = append(analyzers, a) } roots, err := analyze(ctx, v, []Package{pkg}, analyzers) diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go index be9c0f6ca6..5d957b6f6a 100644 --- a/internal/lsp/source/source_test.go +++ b/internal/lsp/source/source_test.go @@ -55,7 +55,7 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) { if err != nil { t.Fatal(err) } - results, err := source.Diagnostics(context.Background(), r.view, f.(source.GoFile)) + results, err := source.Diagnostics(context.Background(), r.view, f.(source.GoFile), nil) if err != nil { t.Fatal(err) }