gopkg.in/golangci/golangci-lint.v1@v1.10.1/pkg/golinters/lll.go (about)

     1  package golinters
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"go/token"
     8  	"os"
     9  	"strings"
    10  	"unicode/utf8"
    11  
    12  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    13  	"github.com/golangci/golangci-lint/pkg/result"
    14  )
    15  
    16  type Lll struct{}
    17  
    18  func (Lll) Name() string {
    19  	return "lll"
    20  }
    21  
    22  func (Lll) Desc() string {
    23  	return "Reports long lines"
    24  }
    25  
    26  func (lint Lll) getIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]result.Issue, error) {
    27  	var res []result.Issue
    28  
    29  	f, err := os.Open(filename)
    30  	if err != nil {
    31  		return nil, fmt.Errorf("can't open file %s: %s", filename, err)
    32  	}
    33  	defer f.Close()
    34  
    35  	lineNumber := 1
    36  	scanner := bufio.NewScanner(f)
    37  	for scanner.Scan() {
    38  		line := scanner.Text()
    39  		line = strings.Replace(line, "\t", tabSpaces, -1)
    40  		lineLen := utf8.RuneCountInString(line)
    41  		if lineLen > maxLineLen {
    42  			res = append(res, result.Issue{
    43  				Pos: token.Position{
    44  					Filename: filename,
    45  					Line:     lineNumber,
    46  				},
    47  				Text:       fmt.Sprintf("line is %d characters", lineLen),
    48  				FromLinter: lint.Name(),
    49  			})
    50  		}
    51  		lineNumber++
    52  	}
    53  
    54  	if err := scanner.Err(); err != nil {
    55  		if err == bufio.ErrTooLong && maxLineLen < bufio.MaxScanTokenSize {
    56  			// scanner.Scan() might fail if the line is longer than bufio.MaxScanTokenSize
    57  			// In the case where the specified maxLineLen is smaller than bufio.MaxScanTokenSize
    58  			// we can return this line as a long line instead of returning an error.
    59  			// The reason for this change is that this case might happen with autogenerated files
    60  			// The go-bindata tool for instance might generate a file with a very long line.
    61  			// In this case, as it's a auto generated file, the warning returned by lll will
    62  			// be ignored.
    63  			// But if we return a linter error here, and this error happens for an autogenerated
    64  			// file the error will be discarded (fine), but all the subsequent errors for lll will
    65  			// be discarded for other files and we'll miss legit error.
    66  			res = append(res, result.Issue{
    67  				Pos: token.Position{
    68  					Filename: filename,
    69  					Line:     lineNumber,
    70  					Column:   1,
    71  				},
    72  				Text:       fmt.Sprintf("line is more than %d characters", bufio.MaxScanTokenSize),
    73  				FromLinter: lint.Name(),
    74  			})
    75  		} else {
    76  			return nil, fmt.Errorf("can't scan file %s: %s", filename, err)
    77  		}
    78  	}
    79  
    80  	return res, nil
    81  }
    82  
    83  func (lint Lll) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
    84  	var res []result.Issue
    85  	spaces := strings.Repeat(" ", lintCtx.Settings().Lll.TabWidth)
    86  	for _, f := range lintCtx.PkgProgram.Files(lintCtx.Cfg.Run.AnalyzeTests) {
    87  		issues, err := lint.getIssuesForFile(f, lintCtx.Settings().Lll.LineLength, spaces)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  		res = append(res, issues...)
    92  	}
    93  
    94  	return res, nil
    95  }