internal/lsp: temporarily disable type error analyzers by default

If we release gopls/v0.4.0 soon, we should keep these new analyzers off
by default. They were just merged, so they haven't been used enough to
be enabled, I think. We'll turn them on by default for gopls/v0.5.0.

Also, ended up creating a helper function to check if analysis has been
abled (which fixed a small bug in FindAnalysisError), and another helper
function to enable all analyses for testing purposes.

Updates golang/go#38212

Change-Id: I5ee94b3582dfc0863978650fc6ce51bfa0606c13
Reviewed-on: https://go-review.googlesource.com/c/tools/+/226962
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rohan Challa <rohan@golang.org>
diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md
index 90cf758..f3e5eee 100644
--- a/gopls/doc/analyzers.md
+++ b/gopls/doc/analyzers.md
@@ -341,6 +341,8 @@
 
 This functionality is similar to [goreturns](https://github.com/sqs/goreturns).
 
+Default value: `false`.
+
 ### **nonewvars**
 
 suggested fixes for "no new vars on left side of :="
@@ -357,7 +359,7 @@
 z = 2
 ```
 
-Default value: `true`.
+Default value: `false`.
 
 ### **noresultvalues**
 
@@ -471,7 +473,7 @@
 type `undeclared name: <>`. It will insert a new statement:
 `<> := `.
 
-Default value: `true`.
+Default value: `false`.
 
 ### **unusedparams**
 
diff --git a/gopls/internal/hooks/analysis.go b/gopls/internal/hooks/analysis.go
index 338827a..3a4c00f 100644
--- a/gopls/internal/hooks/analysis.go
+++ b/gopls/internal/hooks/analysis.go
@@ -14,17 +14,17 @@
 func updateAnalyzers(options *source.Options) {
 	if options.StaticCheck {
 		for _, a := range simple.Analyzers {
-			options.DefaultAnalyzers[a.Name] = source.Analyzer{Analyzer: a, Enabled: true}
+			options.AddDefaultAnalyzer(a)
 		}
 		for _, a := range staticcheck.Analyzers {
 			// This check conflicts with the vet printf check (golang/go#34494).
 			if a.Name == "SA5009" {
 				continue
 			}
-			options.DefaultAnalyzers[a.Name] = source.Analyzer{Analyzer: a, Enabled: true}
+			options.AddDefaultAnalyzer(a)
 		}
 		for _, a := range stylecheck.Analyzers {
-			options.DefaultAnalyzers[a.Name] = source.Analyzer{Analyzer: a, Enabled: true}
+			options.AddDefaultAnalyzer(a)
 		}
 	}
 }
diff --git a/internal/lsp/cache/pkg.go b/internal/lsp/cache/pkg.go
index 4e51038..9fe7a02 100644
--- a/internal/lsp/cache/pkg.go
+++ b/internal/lsp/cache/pkg.go
@@ -131,10 +131,9 @@
 	if analyzer.Analyzer == nil {
 		return nil, nil, errors.Errorf("unexpected analyzer: %s", analyzerName)
 	}
-	if !analyzer.Enabled {
+	if !analyzer.Enabled(s) {
 		return nil, nil, errors.Errorf("disabled analyzer: %s", analyzerName)
 	}
-
 	act, err := s.actionHandle(ctx, packageID(pkgID), analyzer.Analyzer)
 	if err != nil {
 		return nil, nil, err
diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go
index 299bc59..f667c46 100644
--- a/internal/lsp/cmd/cmd.go
+++ b/internal/lsp/cmd/cmd.go
@@ -263,7 +263,6 @@
 	params.InitializationOptions = map[string]interface{}{
 		"matcher": matcherString[opts.Matcher],
 	}
-
 	if _, err := c.Server.Initialize(ctx, params); err != nil {
 		return err
 	}
@@ -374,8 +373,13 @@
 			env[l[0]] = l[1]
 		}
 		results[i] = map[string]interface{}{
-			"env":     env,
-			"go-diff": true,
+			"env": env,
+			"analyses": map[string]bool{
+				"fillreturns":    true,
+				"nonewvars":      true,
+				"noresultvalues": true,
+				"undeclaredname": true,
+			},
 		}
 	}
 	return results, nil
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 1d3fd86..0b38d1d 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -54,10 +54,16 @@
 		options := tests.DefaultOptions()
 		session.SetOptions(options)
 		options.Env = datum.Config.Env
-		v, _, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options)
+		v, snapshot, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options)
 		if err != nil {
 			t.Fatal(err)
 		}
+
+		// Enable type error analyses for tests.
+		// TODO(golang/go#38212): Delete this once they are enabled by default.
+		tests.EnableAllAnalyzers(snapshot, &options)
+		v.SetOptions(ctx, options)
+
 		// Check to see if the -modfile flag is available, this is basically a check
 		// to see if the go version >= 1.14. Otherwise, the modfile specific tests
 		// will always fail if this flag is not available.
diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go
index b5b0444..2c97cba 100644
--- a/internal/lsp/source/diagnostics.go
+++ b/internal/lsp/source/diagnostics.go
@@ -274,14 +274,8 @@
 
 func analyses(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][]Diagnostic, ph PackageHandle, analyses map[string]Analyzer) error {
 	var analyzers []*analysis.Analyzer
-	for name, a := range analyses {
-		if enabled, ok := snapshot.View().Options().UserEnabledAnalyses[name]; ok {
-			if enabled {
-				analyzers = append(analyzers, a.Analyzer)
-			}
-			continue
-		}
-		if !a.Enabled {
+	for _, a := range analyses {
+		if !a.Enabled(snapshot) {
 			continue
 		}
 		analyzers = append(analyzers, a.Analyzer)
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 98d408d..6b33d63 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -10,6 +10,7 @@
 	"regexp"
 	"time"
 
+	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/asmdecl"
 	"golang.org/x/tools/go/analysis/passes/assign"
 	"golang.org/x/tools/go/analysis/passes/atomic"
@@ -198,6 +199,10 @@
 	TypeErrorAnalyzers map[string]Analyzer
 }
 
+func (o Options) AddDefaultAnalyzer(a *analysis.Analyzer) {
+	o.DefaultAnalyzers[a.Name] = Analyzer{Analyzer: a, enabled: true}
+}
+
 type ExperimentalOptions struct {
 	// WARNING: This configuration will be changed in the future.
 	// It only exists while this feature is under development.
@@ -492,49 +497,49 @@
 
 func typeErrorAnalyzers() map[string]Analyzer {
 	return map[string]Analyzer{
-		fillreturns.Analyzer.Name:    {Analyzer: fillreturns.Analyzer, Enabled: true},
-		nonewvars.Analyzer.Name:      {Analyzer: nonewvars.Analyzer, Enabled: true},
-		noresultvalues.Analyzer.Name: {Analyzer: noresultvalues.Analyzer, Enabled: true},
-		undeclaredname.Analyzer.Name: {Analyzer: undeclaredname.Analyzer, Enabled: true},
+		fillreturns.Analyzer.Name:    {Analyzer: fillreturns.Analyzer, enabled: false},
+		nonewvars.Analyzer.Name:      {Analyzer: nonewvars.Analyzer, enabled: false},
+		noresultvalues.Analyzer.Name: {Analyzer: noresultvalues.Analyzer, enabled: false},
+		undeclaredname.Analyzer.Name: {Analyzer: undeclaredname.Analyzer, enabled: false},
 	}
 }
 
 func defaultAnalyzers() map[string]Analyzer {
 	return map[string]Analyzer{
 		// The traditional vet suite:
-		asmdecl.Analyzer.Name:      {Analyzer: asmdecl.Analyzer, Enabled: true},
-		assign.Analyzer.Name:       {Analyzer: assign.Analyzer, Enabled: true},
-		atomic.Analyzer.Name:       {Analyzer: atomic.Analyzer, Enabled: true},
-		atomicalign.Analyzer.Name:  {Analyzer: atomicalign.Analyzer, Enabled: true},
-		bools.Analyzer.Name:        {Analyzer: bools.Analyzer, Enabled: true},
-		buildtag.Analyzer.Name:     {Analyzer: buildtag.Analyzer, Enabled: true},
-		cgocall.Analyzer.Name:      {Analyzer: cgocall.Analyzer, Enabled: true},
-		composite.Analyzer.Name:    {Analyzer: composite.Analyzer, Enabled: true},
-		copylock.Analyzer.Name:     {Analyzer: copylock.Analyzer, Enabled: true},
-		errorsas.Analyzer.Name:     {Analyzer: errorsas.Analyzer, Enabled: true},
-		httpresponse.Analyzer.Name: {Analyzer: httpresponse.Analyzer, Enabled: true},
-		loopclosure.Analyzer.Name:  {Analyzer: loopclosure.Analyzer, Enabled: true},
-		lostcancel.Analyzer.Name:   {Analyzer: lostcancel.Analyzer, Enabled: true},
-		nilfunc.Analyzer.Name:      {Analyzer: nilfunc.Analyzer, Enabled: true},
-		printf.Analyzer.Name:       {Analyzer: printf.Analyzer, Enabled: true},
-		shift.Analyzer.Name:        {Analyzer: shift.Analyzer, Enabled: true},
-		stdmethods.Analyzer.Name:   {Analyzer: stdmethods.Analyzer, Enabled: true},
-		structtag.Analyzer.Name:    {Analyzer: structtag.Analyzer, Enabled: true},
-		tests.Analyzer.Name:        {Analyzer: tests.Analyzer, Enabled: true},
-		unmarshal.Analyzer.Name:    {Analyzer: unmarshal.Analyzer, Enabled: true},
-		unreachable.Analyzer.Name:  {Analyzer: unreachable.Analyzer, Enabled: true},
-		unsafeptr.Analyzer.Name:    {Analyzer: unsafeptr.Analyzer, Enabled: true},
-		unusedresult.Analyzer.Name: {Analyzer: unusedresult.Analyzer, Enabled: true},
+		asmdecl.Analyzer.Name:      {Analyzer: asmdecl.Analyzer, enabled: true},
+		assign.Analyzer.Name:       {Analyzer: assign.Analyzer, enabled: true},
+		atomic.Analyzer.Name:       {Analyzer: atomic.Analyzer, enabled: true},
+		atomicalign.Analyzer.Name:  {Analyzer: atomicalign.Analyzer, enabled: true},
+		bools.Analyzer.Name:        {Analyzer: bools.Analyzer, enabled: true},
+		buildtag.Analyzer.Name:     {Analyzer: buildtag.Analyzer, enabled: true},
+		cgocall.Analyzer.Name:      {Analyzer: cgocall.Analyzer, enabled: true},
+		composite.Analyzer.Name:    {Analyzer: composite.Analyzer, enabled: true},
+		copylock.Analyzer.Name:     {Analyzer: copylock.Analyzer, enabled: true},
+		errorsas.Analyzer.Name:     {Analyzer: errorsas.Analyzer, enabled: true},
+		httpresponse.Analyzer.Name: {Analyzer: httpresponse.Analyzer, enabled: true},
+		loopclosure.Analyzer.Name:  {Analyzer: loopclosure.Analyzer, enabled: true},
+		lostcancel.Analyzer.Name:   {Analyzer: lostcancel.Analyzer, enabled: true},
+		nilfunc.Analyzer.Name:      {Analyzer: nilfunc.Analyzer, enabled: true},
+		printf.Analyzer.Name:       {Analyzer: printf.Analyzer, enabled: true},
+		shift.Analyzer.Name:        {Analyzer: shift.Analyzer, enabled: true},
+		stdmethods.Analyzer.Name:   {Analyzer: stdmethods.Analyzer, enabled: true},
+		structtag.Analyzer.Name:    {Analyzer: structtag.Analyzer, enabled: true},
+		tests.Analyzer.Name:        {Analyzer: tests.Analyzer, enabled: true},
+		unmarshal.Analyzer.Name:    {Analyzer: unmarshal.Analyzer, enabled: true},
+		unreachable.Analyzer.Name:  {Analyzer: unreachable.Analyzer, enabled: true},
+		unsafeptr.Analyzer.Name:    {Analyzer: unsafeptr.Analyzer, enabled: true},
+		unusedresult.Analyzer.Name: {Analyzer: unusedresult.Analyzer, enabled: true},
 
 		// Non-vet analyzers
-		deepequalerrors.Analyzer.Name:  {Analyzer: deepequalerrors.Analyzer, Enabled: true},
-		sortslice.Analyzer.Name:        {Analyzer: sortslice.Analyzer, Enabled: true},
-		testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
-		unusedparams.Analyzer.Name:     {Analyzer: unusedparams.Analyzer, Enabled: false},
+		deepequalerrors.Analyzer.Name:  {Analyzer: deepequalerrors.Analyzer, enabled: true},
+		sortslice.Analyzer.Name:        {Analyzer: sortslice.Analyzer, enabled: true},
+		testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, enabled: true},
+		unusedparams.Analyzer.Name:     {Analyzer: unusedparams.Analyzer, enabled: false},
 
 		// gofmt -s suite:
-		simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, Enabled: true, HighConfidence: true},
-		simplifyrange.Analyzer.Name:        {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
-		simplifyslice.Analyzer.Name:        {Analyzer: simplifyslice.Analyzer, Enabled: true, HighConfidence: true},
+		simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, enabled: true, HighConfidence: true},
+		simplifyrange.Analyzer.Name:        {Analyzer: simplifyrange.Analyzer, enabled: true, HighConfidence: true},
+		simplifyslice.Analyzer.Name:        {Analyzer: simplifyslice.Analyzer, enabled: true, HighConfidence: true},
 	}
 }
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index 15a1300..d8933e4 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -51,10 +51,14 @@
 		session := cache.NewSession(ctx)
 		options := tests.DefaultOptions()
 		options.Env = datum.Config.Env
-		view, _, err := session.NewView(ctx, "source_test", span.URIFromPath(datum.Config.Dir), options)
+		view, snapshot, err := session.NewView(ctx, "source_test", span.URIFromPath(datum.Config.Dir), options)
 		if err != nil {
 			t.Fatal(err)
 		}
+		// Enable type error analyses for tests.
+		// TODO(golang/go#38212): Delete this once they are enabled by default.
+		tests.EnableAllAnalyzers(snapshot, &options)
+		view.SetOptions(ctx, options)
 		r := &runner{
 			view: view,
 			data: datum,
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index ab9e666..eba54e6 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -367,13 +367,20 @@
 // that let the user know how to use the analyzer.
 type Analyzer struct {
 	Analyzer *analysis.Analyzer
-	Enabled  bool
+	enabled  bool
 
 	// If this is true, then we can apply the suggested fixes
 	// as part of a source.FixAll codeaction.
 	HighConfidence bool
 }
 
+func (a Analyzer) Enabled(snapshot Snapshot) bool {
+	if enabled, ok := snapshot.View().Options().UserEnabledAnalyses[a.Analyzer.Name]; ok {
+		return enabled
+	}
+	return a.enabled
+}
+
 // Package represents a Go package that has been type-checked. It maintains
 // only the relevant fields of a *go/packages.Package.
 type Package interface {
diff --git a/internal/lsp/tests/util.go b/internal/lsp/tests/util.go
index 8d2fe05..e6de57f 100644
--- a/internal/lsp/tests/util.go
+++ b/internal/lsp/tests/util.go
@@ -503,3 +503,19 @@
 	}
 	return folder
 }
+
+func EnableAllAnalyzers(snapshot source.Snapshot, opts *source.Options) {
+	if opts.UserEnabledAnalyses == nil {
+		opts.UserEnabledAnalyses = make(map[string]bool)
+	}
+	for _, a := range opts.DefaultAnalyzers {
+		if !a.Enabled(snapshot) {
+			opts.UserEnabledAnalyses[a.Analyzer.Name] = true
+		}
+	}
+	for _, a := range opts.TypeErrorAnalyzers {
+		if !a.Enabled(snapshot) {
+			opts.UserEnabledAnalyses[a.Analyzer.Name] = true
+		}
+	}
+}