github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/result/processors/identifier_marker.go (about)

     1  package processors
     2  
     3  import (
     4  	"regexp"
     5  
     6  	"github.com/vanstinator/golangci-lint/pkg/result"
     7  )
     8  
     9  type replacePattern struct {
    10  	re   string
    11  	repl string
    12  }
    13  
    14  type replaceRegexp struct {
    15  	re   *regexp.Regexp
    16  	repl string
    17  }
    18  
    19  var replacePatterns = []replacePattern{
    20  	// unparam
    21  	{`^(\S+) - (\S+) is unused$`, "`${1}` - `${2}` is unused"},
    22  	{`^(\S+) - (\S+) always receives (\S+) \((.*)\)$`, "`${1}` - `${2}` always receives `${3}` (`${4}`)"},
    23  	{`^(\S+) - (\S+) always receives (.*)$`, "`${1}` - `${2}` always receives `${3}`"},
    24  	{`^(\S+) - result (\S+) is always (\S+)`, "`${1}` - result `${2}` is always `${3}`"},
    25  
    26  	// interfacer
    27  	{`^(\S+) can be (\S+)$`, "`${1}` can be `${2}`"},
    28  
    29  	// govet
    30  	{`^printf: (\S+) arg list ends with redundant newline$`, "printf: `${1}` arg list ends with redundant newline"},
    31  	{`^composites: (\S+) composite literal uses unkeyed fields$`, "composites: `${1}` composite literal uses unkeyed fields"},
    32  
    33  	// gosec
    34  	{`^(\S+): Blacklisted import (\S+): weak cryptographic primitive$`,
    35  		"${1}: Blacklisted import `${2}`: weak cryptographic primitive"},
    36  	{`^TLS InsecureSkipVerify set true.$`, "TLS `InsecureSkipVerify` set true."},
    37  
    38  	// gosimple
    39  	{`should replace loop with (.*)$`, "should replace loop with `${1}`"},
    40  	{`should use a simple channel send/receive instead of select with a single case`,
    41  		"should use a simple channel send/receive instead of `select` with a single case"},
    42  	{`should omit comparison to bool constant, can be simplified to (.+)$`,
    43  		"should omit comparison to bool constant, can be simplified to `${1}`"},
    44  	{`should write (.+) instead of (.+)$`, "should write `${1}` instead of `${2}`"},
    45  	{`redundant return statement$`, "redundant `return` statement"},
    46  	{`should replace this if statement with an unconditional strings.TrimPrefix`,
    47  		"should replace this `if` statement with an unconditional `strings.TrimPrefix`"},
    48  
    49  	// staticcheck
    50  	{`this value of (\S+) is never used$`, "this value of `${1}` is never used"},
    51  	{`should use time.Since instead of time.Now\(\).Sub$`,
    52  		"should use `time.Since` instead of `time.Now().Sub`"},
    53  	{`should check returned error before deferring response.Close\(\)$`,
    54  		"should check returned error before deferring `response.Close()`"},
    55  	{`no value of type uint is less than 0$`, "no value of type `uint` is less than `0`"},
    56  
    57  	// unused
    58  	{`(func|const|field|type|var) (\S+) is unused$`, "${1} `${2}` is unused"},
    59  
    60  	// typecheck
    61  	{`^unknown field (\S+) in struct literal$`, "unknown field `${1}` in struct literal"},
    62  	{`^invalid operation: (\S+) \(variable of type (\S+)\) has no field or method (\S+)$`,
    63  		"invalid operation: `${1}` (variable of type `${2}`) has no field or method `${3}`"},
    64  	{`^undeclared name: (\S+)$`, "undeclared name: `${1}`"},
    65  	{`^cannot use addr \(variable of type (\S+)\) as (\S+) value in argument to (\S+)$`,
    66  		"cannot use addr (variable of type `${1}`) as `${2}` value in argument to `${3}`"},
    67  	{`^other declaration of (\S+)$`, "other declaration of `${1}`"},
    68  	{`^(\S+) redeclared in this block$`, "`${1}` redeclared in this block"},
    69  
    70  	// golint
    71  	{`^exported (type|method|function|var|const) (\S+) should have comment or be unexported$`,
    72  		"exported ${1} `${2}` should have comment or be unexported"},
    73  	{`^comment on exported (type|method|function|var|const) (\S+) should be of the form "(\S+) ..."$`,
    74  		"comment on exported ${1} `${2}` should be of the form `${3} ...`"},
    75  	{`^should replace (.+) with (.+)$`, "should replace `${1}` with `${2}`"},
    76  	{`^if block ends with a return statement, so drop this else and outdent its block$`,
    77  		"`if` block ends with a `return` statement, so drop this `else` and outdent its block"},
    78  	{`^(struct field|var|range var|const|type|(?:func|method|interface method) (?:parameter|result)) (\S+) should be (\S+)$`,
    79  		"${1} `${2}` should be `${3}`"},
    80  	{`^don't use underscores in Go names; var (\S+) should be (\S+)$`,
    81  		"don't use underscores in Go names; var `${1}` should be `${2}`"},
    82  }
    83  
    84  type IdentifierMarker struct {
    85  	replaceRegexps []replaceRegexp
    86  }
    87  
    88  func NewIdentifierMarker() *IdentifierMarker {
    89  	var replaceRegexps []replaceRegexp
    90  	for _, p := range replacePatterns {
    91  		r := replaceRegexp{
    92  			re:   regexp.MustCompile(p.re),
    93  			repl: p.repl,
    94  		}
    95  		replaceRegexps = append(replaceRegexps, r)
    96  	}
    97  
    98  	return &IdentifierMarker{
    99  		replaceRegexps: replaceRegexps,
   100  	}
   101  }
   102  
   103  func (im IdentifierMarker) Process(issues []result.Issue) ([]result.Issue, error) {
   104  	return transformIssues(issues, func(i *result.Issue) *result.Issue {
   105  		iCopy := *i
   106  		iCopy.Text = im.markIdentifiers(iCopy.Text)
   107  		return &iCopy
   108  	}), nil
   109  }
   110  
   111  func (im IdentifierMarker) markIdentifiers(s string) string {
   112  	for _, rr := range im.replaceRegexps {
   113  		rs := rr.re.ReplaceAllString(s, rr.repl)
   114  		if rs != s {
   115  			return rs
   116  		}
   117  	}
   118  
   119  	return s
   120  }
   121  
   122  func (im IdentifierMarker) Name() string {
   123  	return "identifier_marker"
   124  }
   125  func (im IdentifierMarker) Finish() {}