golang.org/x/tools/gopls@v0.15.3/internal/analysis/noresultvalues/noresultvalues.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package noresultvalues
     6  
     7  import (
     8  	"bytes"
     9  	"go/ast"
    10  	"go/format"
    11  	"strings"
    12  
    13  	_ "embed"
    14  
    15  	"golang.org/x/tools/go/analysis"
    16  	"golang.org/x/tools/go/analysis/passes/inspect"
    17  	"golang.org/x/tools/go/ast/inspector"
    18  	"golang.org/x/tools/internal/analysisinternal"
    19  )
    20  
    21  //go:embed doc.go
    22  var doc string
    23  
    24  var Analyzer = &analysis.Analyzer{
    25  	Name:             "noresultvalues",
    26  	Doc:              analysisinternal.MustExtractDoc(doc, "noresultvalues"),
    27  	Requires:         []*analysis.Analyzer{inspect.Analyzer},
    28  	Run:              run,
    29  	RunDespiteErrors: true,
    30  	URL:              "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/noresultvars",
    31  }
    32  
    33  func run(pass *analysis.Pass) (interface{}, error) {
    34  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    35  	if len(pass.TypeErrors) == 0 {
    36  		return nil, nil
    37  	}
    38  
    39  	nodeFilter := []ast.Node{(*ast.ReturnStmt)(nil)}
    40  	inspect.Preorder(nodeFilter, func(n ast.Node) {
    41  		retStmt, _ := n.(*ast.ReturnStmt)
    42  
    43  		var file *ast.File
    44  		for _, f := range pass.Files {
    45  			if f.Pos() <= retStmt.Pos() && retStmt.Pos() < f.End() {
    46  				file = f
    47  				break
    48  			}
    49  		}
    50  		if file == nil {
    51  			return
    52  		}
    53  
    54  		for _, err := range pass.TypeErrors {
    55  			if !FixesError(err.Msg) {
    56  				continue
    57  			}
    58  			if retStmt.Pos() >= err.Pos || err.Pos >= retStmt.End() {
    59  				continue
    60  			}
    61  			var buf bytes.Buffer
    62  			if err := format.Node(&buf, pass.Fset, file); err != nil {
    63  				continue
    64  			}
    65  			pass.Report(analysis.Diagnostic{
    66  				Pos:     err.Pos,
    67  				End:     analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos),
    68  				Message: err.Msg,
    69  				SuggestedFixes: []analysis.SuggestedFix{{
    70  					Message: "Delete return values",
    71  					TextEdits: []analysis.TextEdit{{
    72  						Pos:     retStmt.Pos(),
    73  						End:     retStmt.End(),
    74  						NewText: []byte("return"),
    75  					}},
    76  				}},
    77  			})
    78  		}
    79  	})
    80  	return nil, nil
    81  }
    82  
    83  func FixesError(msg string) bool {
    84  	return msg == "no result values expected" ||
    85  		strings.HasPrefix(msg, "too many return values") && strings.Contains(msg, "want ()")
    86  }