github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/line-length-limit.go (about)

     1  package rule
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"go/token"
     8  	"strings"
     9  	"unicode/utf8"
    10  
    11  	"github.com/songshiyun/revive/lint"
    12  )
    13  
    14  // LineLengthLimitRule lints given else constructs.
    15  type LineLengthLimitRule struct {
    16  	max int
    17  }
    18  
    19  // Apply applies the rule to given file.
    20  func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
    21  	if r.max == 0 {
    22  		checkNumberOfArguments(1, arguments, r.Name())
    23  
    24  		max, ok := arguments[0].(int64) // Alt. non panicking version
    25  		if !ok || max < 0 {
    26  			panic(`invalid value passed as argument number to the "line-length-limit" rule`)
    27  		}
    28  
    29  		r.max = int(max)
    30  	}
    31  
    32  	var failures []lint.Failure
    33  	checker := lintLineLengthNum{
    34  		max:  r.max,
    35  		file: file,
    36  		onFailure: func(failure lint.Failure) {
    37  			failures = append(failures, failure)
    38  		},
    39  	}
    40  
    41  	checker.check()
    42  
    43  	return failures
    44  }
    45  
    46  // Name returns the rule name.
    47  func (r *LineLengthLimitRule) Name() string {
    48  	return "line-length-limit"
    49  }
    50  
    51  type lintLineLengthNum struct {
    52  	max       int
    53  	file      *lint.File
    54  	onFailure func(lint.Failure)
    55  }
    56  
    57  func (r lintLineLengthNum) check() {
    58  	f := bytes.NewReader(r.file.Content())
    59  	spaces := strings.Repeat(" ", 4) // tab width = 4
    60  	l := 1
    61  	s := bufio.NewScanner(f)
    62  	for s.Scan() {
    63  		t := s.Text()
    64  		t = strings.ReplaceAll(t, "\t", spaces)
    65  		c := utf8.RuneCountInString(t)
    66  		if c > r.max {
    67  			r.onFailure(lint.Failure{
    68  				Category: "code-style",
    69  				Position: lint.FailurePosition{
    70  					// Offset not set; it is non-trivial, and doesn't appear to be needed.
    71  					Start: token.Position{
    72  						Filename: r.file.Name,
    73  						Line:     l,
    74  						Column:   0,
    75  					},
    76  					End: token.Position{
    77  						Filename: r.file.Name,
    78  						Line:     l,
    79  						Column:   c,
    80  					},
    81  				},
    82  				Confidence: 1,
    83  				Failure:    fmt.Sprintf("line is %d characters, out of limit %d", c, r.max),
    84  			})
    85  		}
    86  		l++
    87  	}
    88  }