github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/monkit/unused.go (about)

     1  // Copyright (C) 2020 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  // check-monkit finds problems with using monkit.
     5  package monkit
     6  
     7  import (
     8  	"github.com/elek/golangci-lint/pkg/golinters/goanalysis"
     9  	"go/ast"
    10  
    11  	"golang.org/x/tools/go/analysis"
    12  	"golang.org/x/tools/go/analysis/passes/inspect"
    13  	"golang.org/x/tools/go/analysis/singlechecker"
    14  	"golang.org/x/tools/go/ast/inspector"
    15  )
    16  
    17  func main() { singlechecker.Main(Analyzer) }
    18  
    19  func NewMonkitCheck() *goanalysis.Linter {
    20  	return goanalysis.NewLinter(
    21  		"monkit",
    22  		"STORJ: check for unfinished calls to mon.Task()(ctx)(&err)",
    23  		[]*analysis.Analyzer{
    24  			Analyzer,
    25  		},
    26  		nil,
    27  	).WithLoadMode(goanalysis.LoadModeWholeProgram)
    28  }
    29  
    30  // Analyzer implements unused task analysis pass.
    31  var Analyzer = &analysis.Analyzer{
    32  	Name:     "monkit",
    33  	Doc:      `check for unfinished calls to mon.Task()(ctx)(&err)`,
    34  	Requires: []*analysis.Analyzer{inspect.Analyzer},
    35  	Run:      run,
    36  }
    37  
    38  func run(pass *analysis.Pass) (interface{}, error) {
    39  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    40  
    41  	nodeFilter := []ast.Node{
    42  		(*ast.CallExpr)(nil),
    43  	}
    44  	inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) (proceed bool) {
    45  		if push {
    46  			return true
    47  		}
    48  
    49  		call, ok := n.(*ast.CallExpr)
    50  		if !ok {
    51  			return true // not a call statement
    52  		}
    53  
    54  		typ := pass.TypesInfo.TypeOf(call)
    55  		if typ == nil || typ.String() != `github.com/spacemonkeygo/monkit/v3.Task` {
    56  			return true
    57  		}
    58  
    59  		start := stack[len(stack)-2]
    60  		stop := stack[len(stack)-3]
    61  
    62  		if _, ok = start.(*ast.CallExpr); !ok {
    63  			if _, ok := start.(*ast.AssignStmt); ok {
    64  				return true
    65  			}
    66  			if _, ok := start.(*ast.ValueSpec); ok {
    67  				return true
    68  			}
    69  			pass.Reportf(call.Lparen, "monitoring not started")
    70  			return true
    71  		}
    72  		if _, ok = stop.(*ast.CallExpr); !ok {
    73  			if _, ok := stop.(*ast.AssignStmt); ok {
    74  				return true
    75  			}
    76  			pass.Reportf(call.Lparen, "monitoring not stopped")
    77  			return true
    78  		}
    79  
    80  		return true
    81  	})
    82  	return nil, nil
    83  }