Fix #96: support lll

This commit is contained in:
Denis Isaev 2018-06-28 22:39:23 +03:00 committed by Isaev Denis
parent 7b2a63dfa6
commit 1a9af12d6d
17 changed files with 207 additions and 46 deletions

View File

@ -104,6 +104,9 @@ linters-settings:
# Default is to use a neutral variety of English. # Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'. # Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US locale: US
lll:
# max line length, lines longer will be reported. Default is 120. '\t' is counted as 1 character.
line-length: 120
linters: linters:
enable: enable:

View File

@ -114,6 +114,7 @@ maligned: Tool to detect Go structs that would take less memory if their fields
megacheck: 3 sub-linters in one: unused, gosimple and staticcheck [fast: false] megacheck: 3 sub-linters in one: unused, gosimple and staticcheck [fast: false]
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: false] depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: false]
misspell: Finds commonly misspelled English words in comments [fast: true] misspell: Finds commonly misspelled English words in comments [fast: true]
lll: Reports long lines [fast: true]
``` ```
Pass `-E/--enable` to enable linter and `-D/--disable` to disable: Pass `-E/--enable` to enable linter and `-D/--disable` to disable:
@ -220,6 +221,7 @@ golangci-lint linters
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - 3 sub-linters in one: unused, gosimple and staticcheck - [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - 3 sub-linters in one: unused, gosimple and staticcheck
- [depguard](https://github.com/OpenPeeDeeP/depguard) - Go linter that checks if package imports are in a list of acceptable packages - [depguard](https://github.com/OpenPeeDeeP/depguard) - Go linter that checks if package imports are in a list of acceptable packages
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words in comments - [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words in comments
- [lll](https://github.com/walle/lll) - Reports long lines
# Configuration # Configuration
The config file has lower priority than command-line options. If the same bool/string/int option is provided on the command-line The config file has lower priority than command-line options. If the same bool/string/int option is provided on the command-line
@ -422,6 +424,9 @@ linters-settings:
# Default is to use a neutral variety of English. # Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'. # Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US locale: US
lll:
# max line length, lines longer will be reported. Default is 120. '\t' is counted as 1 character.
line-length: 120
linters: linters:
enable: enable:
@ -601,6 +606,7 @@ Thanks to developers and authors of used linters:
- [alecthomas](https://github.com/alecthomas) - [alecthomas](https://github.com/alecthomas)
- [OpenPeeDeeP](https://github.com/OpenPeeDeeP) - [OpenPeeDeeP](https://github.com/OpenPeeDeeP)
- [client9](https://github.com/client9) - [client9](https://github.com/client9)
- [walle](https://github.com/walle)
# Future Plans # Future Plans
1. Upstream all changes of forked linters. 1. Upstream all changes of forked linters.

View File

@ -23,7 +23,7 @@ type Executor struct {
func NewExecutor(version, commit, date string) *Executor { func NewExecutor(version, commit, date string) *Executor {
e := &Executor{ e := &Executor{
cfg: &config.Config{}, cfg: config.NewDefault(),
version: version, version: version,
commit: commit, commit: commit,
date: date, date: date,

View File

@ -32,7 +32,8 @@ func getDefaultExcludeHelp() string {
return strings.Join(parts, "\n") return strings.Join(parts, "\n")
} }
const welcomeMessage = "Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)" const welcomeMessage = "Run this tool in cloud on every github pull " +
"request in https://golangci.com for free (public repos)"
func wh(text string) string { func wh(text string) string {
return color.GreenString(text) return color.GreenString(text)
@ -62,7 +63,8 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
fs.StringSliceVar(&rc.BuildTags, "build-tags", nil, wh("Build tags")) fs.StringSliceVar(&rc.BuildTags, "build-tags", nil, wh("Build tags"))
fs.DurationVar(&rc.Deadline, "deadline", time.Minute, wh("Deadline for total work")) fs.DurationVar(&rc.Deadline, "deadline", time.Minute, wh("Deadline for total work"))
fs.BoolVar(&rc.AnalyzeTests, "tests", true, wh("Analyze tests (*_test.go)")) fs.BoolVar(&rc.AnalyzeTests, "tests", true, wh("Analyze tests (*_test.go)"))
fs.BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false, wh("Print avg and max memory usage of golangci-lint and total time")) fs.BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false,
wh("Print avg and max memory usage of golangci-lint and total time"))
fs.StringVarP(&rc.Config, "config", "c", "", wh("Read config from file path `PATH`")) fs.StringVarP(&rc.Config, "config", "c", "", wh("Read config from file path `PATH`"))
fs.BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config")) fs.BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config"))
fs.StringSliceVar(&rc.SkipDirs, "skip-dirs", nil, wh("Regexps of directories to skip")) fs.StringSliceVar(&rc.SkipDirs, "skip-dirs", nil, wh("Regexps of directories to skip"))
@ -75,16 +77,20 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
// but when number of linters started to grow it became ovious that // but when number of linters started to grow it became ovious that
// we can't fill 90% of flags by linters settings: common flags became hard to find. // we can't fill 90% of flags by linters settings: common flags became hard to find.
// New linters settings should be done only through config file. // New linters settings should be done only through config file.
fs.BoolVar(&lsc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results") fs.BoolVar(&lsc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions",
false, "Errcheck: check for ignored type assertion results")
hideFlag("errcheck.check-type-assertions") hideFlag("errcheck.check-type-assertions")
fs.BoolVar(&lsc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()") fs.BoolVar(&lsc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false,
"Errcheck: check for errors assigned to blank identifier: _ = errFunc()")
hideFlag("errcheck.check-blank") hideFlag("errcheck.check-blank")
fs.BoolVar(&lsc.Govet.CheckShadowing, "govet.check-shadowing", false, "Govet: check for shadowed variables") fs.BoolVar(&lsc.Govet.CheckShadowing, "govet.check-shadowing", false,
"Govet: check for shadowed variables")
hideFlag("govet.check-shadowing") hideFlag("govet.check-shadowing")
fs.Float64Var(&lsc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it") fs.Float64Var(&lsc.Golint.MinConfidence, "golint.min-confidence", 0.8,
"Golint: minimum confidence of a problem to print it")
hideFlag("golint.min-confidence") hideFlag("golint.min-confidence")
fs.BoolVar(&lsc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code") fs.BoolVar(&lsc.Gofmt.Simplify, "gofmt.simplify", true, "Gofmt: simplify code")
@ -94,7 +100,8 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
30, "Minimal complexity of function to report it") 30, "Minimal complexity of function to report it")
hideFlag("gocyclo.min-complexity") hideFlag("gocyclo.min-complexity")
fs.BoolVar(&lsc.Maligned.SuggestNewOrder, "maligned.suggest-new", false, "Maligned: print suggested more optimal struct fields ordering") fs.BoolVar(&lsc.Maligned.SuggestNewOrder, "maligned.suggest-new", false,
"Maligned: print suggested more optimal struct fields ordering")
hideFlag("maligned.suggest-new") hideFlag("maligned.suggest-new")
fs.IntVar(&lsc.Dupl.Threshold, "dupl.threshold", fs.IntVar(&lsc.Dupl.Threshold, "dupl.threshold",
@ -124,7 +131,8 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
fs.BoolVar(&lc.EnableAll, "enable-all", false, wh("Enable all linters")) fs.BoolVar(&lc.EnableAll, "enable-all", false, wh("Enable all linters"))
fs.BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters")) fs.BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters"))
fs.StringSliceVarP(&lc.Presets, "presets", "p", nil, fs.StringSliceVarP(&lc.Presets, "presets", "p", nil,
wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|")))) wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see "+
"them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|"))))
fs.BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set")) fs.BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set"))
// Issues config // Issues config
@ -132,13 +140,20 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
fs.StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", nil, wh("Exclude issue by regexp")) fs.StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", nil, wh("Exclude issue by regexp"))
fs.BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultExcludeHelp()) fs.BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultExcludeHelp())
fs.IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50, wh("Maximum issues count per one linter. Set to 0 to disable")) fs.IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50,
fs.IntVar(&ic.MaxSameIssues, "max-same-issues", 3, wh("Maximum count of issues with the same text. Set to 0 to disable")) wh("Maximum issues count per one linter. Set to 0 to disable"))
fs.IntVar(&ic.MaxSameIssues, "max-same-issues", 3,
wh("Maximum count of issues with the same text. Set to 0 to disable"))
fs.BoolVarP(&ic.Diff, "new", "n", false, fs.BoolVarP(&ic.Diff, "new", "n", false,
wh("Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\nIt's a super-useful option for integration of golangci-lint into existing large codebase.\nIt's not practical to fix all existing issues at the moment of integration: much better don't allow issues in new code")) wh("Show only new issues: if there are unstaged changes or untracked files, only those changes "+
fs.StringVar(&ic.DiffFromRevision, "new-from-rev", "", wh("Show only new issues created after git revision `REV`")) "are analyzed, else only changes in HEAD~ are analyzed.\nIt's a super-useful option for integration "+
fs.StringVar(&ic.DiffPatchFilePath, "new-from-patch", "", wh("Show only new issues created in git patch with file path `PATH`")) "of golangci-lint into existing large codebase.\nIt's not practical to fix all existing issues at "+
"the moment of integration: much better don't allow issues in new code"))
fs.StringVar(&ic.DiffFromRevision, "new-from-rev", "",
wh("Show only new issues created after git revision `REV`"))
fs.StringVar(&ic.DiffPatchFilePath, "new-from-patch", "",
wh("Show only new issues created in git patch with file path `PATH`"))
} }

View File

@ -30,12 +30,14 @@ type ExcludePattern struct {
var DefaultExcludePatterns = []ExcludePattern{ var DefaultExcludePatterns = []ExcludePattern{
{ {
Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked", Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close" +
"|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
Linter: "errcheck", Linter: "errcheck",
Why: "Almost all programs ignore errors on these functions and in most cases it's ok", Why: "Almost all programs ignore errors on these functions and in most cases it's ok",
}, },
{ {
Pattern: "(comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)", Pattern: "(comment on exported (method|function|type|const)|" +
"should have( a package)? comment|comment should be of the form)",
Linter: "golint", Linter: "golint",
Why: "Annoying issue about not having a comment. The rare codebase has such comments", Why: "Annoying issue about not having a comment. The rare codebase has such comments",
}, },
@ -156,6 +158,17 @@ type LintersSettings struct {
Misspell struct { Misspell struct {
Locale string Locale string
} }
Lll LllSettings
}
type LllSettings struct {
LineLength int `mapstructure:"line-length"`
}
var defaultLintersSettings = LintersSettings{
Lll: LllSettings{
LineLength: 120,
},
} }
type Linters struct { type Linters struct {
@ -196,3 +209,9 @@ type Config struct { //nolint:maligned
InternalTest bool // Option is used only for testing golangci-lint code, don't use it InternalTest bool // Option is used only for testing golangci-lint code, don't use it
} }
func NewDefault() *Config {
return &Config{
LintersSettings: defaultLintersSettings,
}
}

View File

@ -16,7 +16,8 @@ func (Errcheck) Name() string {
} }
func (Errcheck) Desc() string { func (Errcheck) Desc() string {
return "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases" return "Errcheck is a program for checking for unchecked errors " +
"in go programs. These unchecked errors can be critical bugs in some cases"
} }
func (e Errcheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { func (e Errcheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {

View File

@ -31,7 +31,8 @@ func (g Gofmt) Desc() string {
return "Goimports does everything that gofmt does. Additionally it checks unused imports" return "Goimports does everything that gofmt does. Additionally it checks unused imports"
} }
return "Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification" return "Gofmt checks whether code was gofmt-ed. By default " +
"this tool runs with -s option to check for code simplification"
} }
func getFirstDeletedAndAddedLineNumberInHunk(h *diff.Hunk) (int, int, error) { func getFirstDeletedAndAddedLineNumberInHunk(h *diff.Hunk) (int, int, error) {

View File

@ -25,7 +25,8 @@ func (Govet) Name() string {
} }
func (Govet) Desc() string { func (Govet) Desc() string {
return "Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string" return "Vet examines Go source code and reports suspicious constructs, " +
"such as Printf calls whose arguments do not align with the format string"
} }
func (g Govet) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { func (g Govet) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {

72
pkg/golinters/lll.go Normal file
View File

@ -0,0 +1,72 @@
package golinters
import (
"bufio"
"context"
"fmt"
"go/token"
"os"
"strings"
"unicode/utf8"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
)
type Lll struct{}
func (Lll) Name() string {
return "lll"
}
func (Lll) Desc() string {
return "Reports long lines"
}
func (lint Lll) getIssuesForFile(filename string, maxLineLen int) ([]result.Issue, error) {
var res []result.Issue
f, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("can't open file %s: %s", filename, err)
}
lineNumber := 1
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
line = strings.Replace(line, "\t", " ", -1)
lineLen := utf8.RuneCountInString(line)
if lineLen > maxLineLen {
res = append(res, result.Issue{
Pos: token.Position{
Filename: filename,
Line: lineNumber,
Column: 1,
},
Text: fmt.Sprintf("line is %d characters", lineLen),
FromLinter: lint.Name(),
})
}
lineNumber++
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("can't scan file %s: %s", filename, err)
}
return res, nil
}
func (lint Lll) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
var res []result.Issue
for _, f := range lintCtx.PkgProgram.Files(lintCtx.Cfg.Run.AnalyzeTests) {
issues, err := lint.getIssuesForFile(f, lintCtx.Settings().Lll.LineLength)
if err != nil {
return nil, err
}
res = append(res, issues...)
}
return res, nil
}

View File

@ -14,7 +14,8 @@ import (
) )
func AllPresets() []string { func AllPresets() []string {
return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting, linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance} return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting,
linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance}
} }
func allPresetsSet() map[string]bool { func allPresetsSet() map[string]bool {
@ -166,6 +167,10 @@ func GetAllSupportedLinterConfigs() []linter.Config {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithSpeed(7). WithSpeed(7).
WithURL("https://github.com/client9/misspell"), WithURL("https://github.com/client9/misspell"),
linter.NewConfig(golinters.Lll{}).
WithPresets(linter.PresetStyle).
WithSpeed(10).
WithURL("https://github.com/walle/lll"),
} }
if os.Getenv("GOLANGCI_COM_RUN") == "1" { if os.Getenv("GOLANGCI_COM_RUN") == "1" {
@ -175,6 +180,7 @@ func GetAllSupportedLinterConfigs() []linter.Config {
golinters.Maligned{}.Name(): true, // rarely usable golinters.Maligned{}.Name(): true, // rarely usable
golinters.TypeCheck{}.Name(): true, // annoying because of different building envs golinters.TypeCheck{}.Name(): true, // annoying because of different building envs
golinters.Misspell{}.Name(): true, // unsure about false-positives number golinters.Misspell{}.Name(): true, // unsure about false-positives number
golinters.Lll{}.Name(): true, // annoying
} }
return enableLinterConfigs(lcs, func(lc *linter.Config) bool { return enableLinterConfigs(lcs, func(lc *linter.Config) bool {
return !disabled[lc.Linter.Name()] return !disabled[lc.Linter.Name()]
@ -314,7 +320,10 @@ func GetAllLinterConfigsForPreset(p string) []linter.Config {
return ret return ret
} }
func getEnabledLintersSet(lcfg *config.Linters, enabledByDefaultLinters []linter.Config) map[string]*linter.Config { // nolint:gocyclo // nolint:gocyclo
func getEnabledLintersSet(lcfg *config.Linters,
enabledByDefaultLinters []linter.Config) map[string]*linter.Config {
resultLintersSet := map[string]*linter.Config{} resultLintersSet := map[string]*linter.Config{}
switch { switch {
case len(lcfg.Presets) != 0: case len(lcfg.Presets) != 0:

View File

@ -109,7 +109,9 @@ func isLocalProjectAnalysis(args []string) bool {
return true return true
} }
func getTypeCheckFuncBodies(cfg *config.Run, linters []linter.Config, pkgProg *packages.Program, log logutils.Log) func(string) bool { func getTypeCheckFuncBodies(cfg *config.Run, linters []linter.Config,
pkgProg *packages.Program, log logutils.Log) func(string) bool {
if !isLocalProjectAnalysis(cfg.Args) { if !isLocalProjectAnalysis(cfg.Args) {
loadDebugf("analysis in nonlocal, don't optimize loading by not typechecking func bodies") loadDebugf("analysis in nonlocal, don't optimize loading by not typechecking func bodies")
return nil return nil
@ -155,7 +157,9 @@ func getTypeCheckFuncBodies(cfg *config.Run, linters []linter.Config, pkgProg *p
} }
} }
func loadWholeAppIfNeeded(ctx context.Context, linters []linter.Config, cfg *config.Config, pkgProg *packages.Program, log logutils.Log) (*loader.Program, *loader.Config, error) { func loadWholeAppIfNeeded(ctx context.Context, linters []linter.Config, cfg *config.Config,
pkgProg *packages.Program, log logutils.Log) (*loader.Program, *loader.Config, error) {
if !isFullImportNeeded(linters, cfg) { if !isFullImportNeeded(linters, cfg) {
return nil, nil, nil return nil, nil, nil
} }
@ -255,7 +259,9 @@ func separateNotCompilingPackages(lintCtx *linter.Context) {
} }
//nolint:gocyclo //nolint:gocyclo
func LoadContext(ctx context.Context, linters []linter.Config, cfg *config.Config, log logutils.Log) (*linter.Context, error) { func LoadContext(ctx context.Context, linters []linter.Config, cfg *config.Config,
log logutils.Log) (*linter.Context, error) {
// Set GOROOT to have working cross-compilation: cross-compiled binaries // Set GOROOT to have working cross-compilation: cross-compiled binaries
// have invalid GOROOT. XXX: can't use runtime.GOROOT(). // have invalid GOROOT. XXX: can't use runtime.GOROOT().
goroot, err := goutils.DiscoverGoRoot() goroot, err := goutils.DiscoverGoRoot()

View File

@ -66,7 +66,9 @@ type lintRes struct {
issues []result.Issue issues []result.Issue
} }
func (r Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, lc linter.Config) (ret []result.Issue, err error) { func (r Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context,
lc linter.Config) (ret []result.Issue, err error) {
defer func() { defer func() {
if panicData := recover(); panicData != nil { if panicData := recover(); panicData != nil {
err = fmt.Errorf("panic occurred: %s", panicData) err = fmt.Errorf("panic occurred: %s", panicData)
@ -88,7 +90,9 @@ func (r Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, lc l
return issues, nil return issues, nil
} }
func (r Runner) runWorker(ctx context.Context, lintCtx *linter.Context, tasksCh <-chan linter.Config, lintResultsCh chan<- lintRes, name string) { func (r Runner) runWorker(ctx context.Context, lintCtx *linter.Context,
tasksCh <-chan linter.Config, lintResultsCh chan<- lintRes, name string) {
sw := timeutils.NewStopwatch(name, r.Log) sw := timeutils.NewStopwatch(name, r.Log)
defer sw.Print() defer sw.Print()

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"strings"
"time" "time"
"github.com/fatih/color" "github.com/fatih/color"
@ -140,18 +139,15 @@ func (p Text) printUnderLinePointer(i *result.Issue, line string) {
return return
} }
var j int col0 := i.Pos.Column - 1
for ; j < len(line) && line[j] == '\t'; j++ { prefixRunes := make([]rune, 0, len(line))
for j := 0; j < len(line) && j < col0; j++ {
if line[j] == '\t' {
prefixRunes = append(prefixRunes, '\t')
} else {
prefixRunes = append(prefixRunes, ' ')
} }
tabsCount := j
spacesCount := i.Pos.Column - 1 - tabsCount
prefix := ""
if tabsCount != 0 {
prefix += strings.Repeat("\t", tabsCount)
}
if spacesCount != 0 {
prefix += strings.Repeat(" ", spacesCount)
} }
fmt.Fprintf(logutils.StdOut, "%s%s\n", prefix, p.SprintfColored(color.FgYellow, "^")) fmt.Fprintf(logutils.StdOut, "%s%s\n", string(prefixRunes), p.SprintfColored(color.FgYellow, "^"))
} }

View File

@ -103,10 +103,12 @@ func getDoc(f *ast.File, fset *token.FileSet, filePath string) string {
var importPos token.Pos var importPos token.Pos
if len(f.Imports) != 0 { if len(f.Imports) != 0 {
importPos = f.Imports[0].Pos() importPos = f.Imports[0].Pos()
autogenDebugf("file %q: search comments until first import pos %d (%s)", filePath, importPos, fset.Position(importPos)) autogenDebugf("file %q: search comments until first import pos %d (%s)",
filePath, importPos, fset.Position(importPos))
} else { } else {
importPos = f.End() importPos = f.End()
autogenDebugf("file %q: search comments until EOF pos %d (%s)", filePath, importPos, fset.Position(importPos)) autogenDebugf("file %q: search comments until EOF pos %d (%s)",
filePath, importPos, fset.Position(importPos))
} }
var neededComments []string var neededComments []string

View File

@ -39,7 +39,8 @@ func TestIsAutogeneratedDetection(t *testing.T) {
// DO NOT EDIT ** This file was generated with the bake tool ** DO NOT EDIT // // DO NOT EDIT ** This file was generated with the bake tool ** DO NOT EDIT //
// Generated by running // Generated by running
// maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt // maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt
// --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
// DO NOT EDIT // DO NOT EDIT
/* /*

6
test/testdata/lll.go vendored Normal file
View File

@ -0,0 +1,6 @@
// args: -Elll
package testdata
func Lll() {
// In my experience, long lines are the lines with comments, not the code. So this is a long comment // ERROR "line is 135 characters"
}

19
third_party/lll/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2016 Fredrik Wallgren
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.