github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/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 defines an Analyzer that applies suggested fixes
     6  // to errors of the type "no result values expected".
     7  package noresultvalues
     8  
     9  import (
    10  	"bytes"
    11  	"go/ast"
    12  	"go/format"
    13  	"strings"
    14  
    15  	"github.com/powerman/golang-tools/go/analysis"
    16  	"github.com/powerman/golang-tools/go/analysis/passes/inspect"
    17  	"github.com/powerman/golang-tools/go/ast/inspector"
    18  	"github.com/powerman/golang-tools/internal/analysisinternal"
    19  )
    20  
    21  const Doc = `suggested fixes for unexpected return values
    22  
    23  This checker provides suggested fixes for type errors of the
    24  type "no result values expected" or "too many return values".
    25  For example:
    26  	func z() { return nil }
    27  will turn into
    28  	func z() { return }
    29  `
    30  
    31  var Analyzer = &analysis.Analyzer{
    32  	Name:             string(analysisinternal.NoResultValues),
    33  	Doc:              Doc,
    34  	Requires:         []*analysis.Analyzer{inspect.Analyzer},
    35  	Run:              run,
    36  	RunDespiteErrors: true,
    37  }
    38  
    39  func run(pass *analysis.Pass) (interface{}, error) {
    40  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    41  	errors := analysisinternal.GetTypeErrors(pass)
    42  
    43  	nodeFilter := []ast.Node{(*ast.ReturnStmt)(nil)}
    44  	inspect.Preorder(nodeFilter, func(n ast.Node) {
    45  		retStmt, _ := n.(*ast.ReturnStmt)
    46  
    47  		var file *ast.File
    48  		for _, f := range pass.Files {
    49  			if f.Pos() <= retStmt.Pos() && retStmt.Pos() < f.End() {
    50  				file = f
    51  				break
    52  			}
    53  		}
    54  		if file == nil {
    55  			return
    56  		}
    57  
    58  		for _, err := range errors {
    59  			if !FixesError(err.Msg) {
    60  				continue
    61  			}
    62  			if retStmt.Pos() >= err.Pos || err.Pos >= retStmt.End() {
    63  				continue
    64  			}
    65  			var buf bytes.Buffer
    66  			if err := format.Node(&buf, pass.Fset, file); err != nil {
    67  				continue
    68  			}
    69  			pass.Report(analysis.Diagnostic{
    70  				Pos:     err.Pos,
    71  				End:     analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos),
    72  				Message: err.Msg,
    73  				SuggestedFixes: []analysis.SuggestedFix{{
    74  					Message: "Delete return values",
    75  					TextEdits: []analysis.TextEdit{{
    76  						Pos:     retStmt.Pos(),
    77  						End:     retStmt.End(),
    78  						NewText: []byte("return"),
    79  					}},
    80  				}},
    81  			})
    82  		}
    83  	})
    84  	return nil, nil
    85  }
    86  
    87  func FixesError(msg string) bool {
    88  	return msg == "no result values expected" ||
    89  		strings.HasPrefix(msg, "too many return values") && strings.Contains(msg, "want ()")
    90  }