github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/unused-param.go (about)

     1  package rule
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  
     7  	"github.com/mgechev/revive/lint"
     8  )
     9  
    10  // UnusedParamRule lints unused params in functions.
    11  type UnusedParamRule struct{}
    12  
    13  // Apply applies the rule to given file.
    14  func (r *UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    15  	var failures []lint.Failure
    16  
    17  	onFailure := func(failure lint.Failure) {
    18  		failures = append(failures, failure)
    19  	}
    20  
    21  	w := lintUnusedParamRule{onFailure: onFailure}
    22  
    23  	ast.Walk(w, file.AST)
    24  
    25  	return failures
    26  }
    27  
    28  // Name returns the rule name.
    29  func (r *UnusedParamRule) Name() string {
    30  	return "unused-parameter"
    31  }
    32  
    33  type lintUnusedParamRule struct {
    34  	onFailure func(lint.Failure)
    35  }
    36  
    37  func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
    38  	switch n := node.(type) {
    39  	case *ast.FuncDecl:
    40  		params := retrieveNamedParams(n.Type.Params)
    41  		if len(params) < 1 {
    42  			return nil // skip, func without parameters
    43  		}
    44  
    45  		if n.Body == nil {
    46  			return nil // skip, is a function prototype
    47  		}
    48  
    49  		// inspect the func body looking for references to parameters
    50  		fselect := func(n ast.Node) bool {
    51  			ident, isAnID := n.(*ast.Ident)
    52  
    53  			if !isAnID {
    54  				return false
    55  			}
    56  
    57  			_, isAParam := params[ident.Obj]
    58  			if isAParam {
    59  				params[ident.Obj] = false // mark as used
    60  			}
    61  
    62  			return false
    63  		}
    64  		_ = pick(n.Body, fselect, nil)
    65  
    66  		for _, p := range n.Type.Params.List {
    67  			for _, n := range p.Names {
    68  				if params[n.Obj] {
    69  					w.onFailure(lint.Failure{
    70  						Confidence: 1,
    71  						Node:       n,
    72  						Category:   "bad practice",
    73  						Failure:    fmt.Sprintf("parameter '%s' seems to be unused, consider removing or renaming it as _", n.Name),
    74  					})
    75  				}
    76  			}
    77  		}
    78  
    79  		return nil // full method body already inspected
    80  	}
    81  
    82  	return w
    83  }
    84  
    85  func retrieveNamedParams(params *ast.FieldList) map[*ast.Object]bool {
    86  	result := map[*ast.Object]bool{}
    87  	if params.List == nil {
    88  		return result
    89  	}
    90  
    91  	for _, p := range params.List {
    92  		for _, n := range p.Names {
    93  			if n.Name == "_" {
    94  				continue
    95  			}
    96  
    97  			result[n.Obj] = true
    98  		}
    99  	}
   100  
   101  	return result
   102  }