Skip to content

Commit 362aea5

Browse files
authored
dev: new processor order (#5322)
1 parent 6d29861 commit 362aea5

25 files changed

+130
-44
lines changed

pkg/fsutils/fsutils.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ func Getwd() (string, error) {
3434
return
3535
}
3636

37-
evaledWd, err := EvalSymlinks(cachedWd)
37+
evaluatedWd, err := EvalSymlinks(cachedWd)
3838
if err != nil {
3939
cachedWd, cachedWdError = "", fmt.Errorf("can't eval symlinks on wd %s: %w", cachedWd, err)
4040
return
4141
}
4242

43-
cachedWd = evaledWd
43+
cachedWd = evaluatedWd
4444
})
4545

4646
return cachedWd, cachedWdError
@@ -83,8 +83,8 @@ func ShortestRelPath(path, wd string) (string, error) {
8383
path = evaledPath
8484

8585
// make path absolute and then relative to be able to fix this case:
86-
// we are in /test dir, we want to normalize ../test, and have file file.go in this dir;
87-
// it must have normalized path file.go, not ../test/file.go,
86+
// we are in `/test` dir, we want to normalize `../test`, and have file `file.go` in this dir;
87+
// it must have normalized path `file.go`, not `../test/file.go`,
8888
var absPath string
8989
if filepath.IsAbs(path) {
9090
absPath = path

pkg/fsutils/fsutils_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package fsutils
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestShortestRelPath(t *testing.T) {
12+
testCases := []struct {
13+
desc string
14+
path string
15+
wd string
16+
expected string
17+
}{
18+
{
19+
desc: "based on parent path",
20+
path: "fsutils_test.go",
21+
wd: filepath.Join("..", "fsutils"),
22+
expected: "fsutils_test.go",
23+
},
24+
{
25+
desc: "based on current working directory",
26+
path: "fsutils_test.go",
27+
wd: "",
28+
expected: "fsutils_test.go",
29+
},
30+
}
31+
32+
for _, test := range testCases {
33+
t.Run(test.desc, func(t *testing.T) {
34+
t.Parallel()
35+
36+
rel, err := ShortestRelPath("fsutils_test.go", filepath.Join("..", "fsutils"))
37+
require.NoError(t, err)
38+
39+
assert.Equal(t, test.expected, rel)
40+
})
41+
}
42+
}

pkg/lint/runner.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
7979
// Must be after FilenameUnadjuster.
8080
processors.NewInvalidIssue(log.Child(logutils.DebugKeyInvalidIssue)),
8181

82-
// Must be before diff, nolint and exclude autogenerated processor at least.
82+
// Must be before Diff, SkipFiles, SkipDirs, ExcludeRules processors at least.
8383
processors.NewPathPrettifier(log),
84+
85+
// must be after PathPrettifier.
8486
skipFilesProcessor,
85-
skipDirsProcessor, // must be after path prettifier
87+
skipDirsProcessor,
8688

8789
processors.NewAutogeneratedExclude(cfg.Issues.ExcludeGenerated),
8890

@@ -94,20 +96,21 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
9496

9597
processors.NewNolint(log.Child(logutils.DebugKeyNolint), dbManager, enabledLinters),
9698

97-
processors.NewUniqByLine(cfg),
9899
processors.NewDiff(&cfg.Issues),
100+
101+
// The fixer still needs to see paths for the issues that are relative to the current directory.
102+
processors.NewFixer(cfg, log, fileCache, metaFormatter),
103+
104+
// Must be after the Fixer.
105+
processors.NewUniqByLine(cfg),
99106
processors.NewMaxPerFileFromLinter(cfg),
100107
processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child(logutils.DebugKeyMaxSameIssues), cfg),
101108
processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child(logutils.DebugKeyMaxFromLinter), cfg),
102109

110+
// Now we can modify the issues for output.
103111
processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)),
104112
processors.NewPathShortener(),
105113
processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), files, &cfg.Severity),
106-
107-
// The fixer still needs to see paths for the issues that are relative to the current directory.
108-
processors.NewFixer(cfg, log, fileCache, metaFormatter),
109-
110-
// Now we can modify the issues for output.
111114
processors.NewPathPrefixer(cfg.Output.PathPrefix),
112115
processors.NewSortResults(cfg),
113116
},

pkg/result/processors/autogenerated_exclude.go

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ type fileSummary struct {
3939
generated bool
4040
}
4141

42+
// AutogeneratedExclude filters generated files.
43+
// - mode "lax": see `isGeneratedFileLax` documentation.
44+
// - mode "strict": see `isGeneratedFileStrict` documentation.
45+
// - mode "disable": skips this processor.
4246
type AutogeneratedExclude struct {
4347
debugf logutils.DebugFunc
4448

pkg/result/processors/cgo.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import (
1010

1111
var _ Processor = (*Cgo)(nil)
1212

13-
// Cgo some linters (e.g. gosec, deadcode) return incorrect filepaths for cgo issues,
14-
// also cgo files have strange issues looking like false positives.
13+
// Cgo filters cgo artifacts.
1514
//
16-
// Require absolute filepath.
15+
// Some linters (e.g. gosec, etc.) return incorrect file paths for cgo files.
16+
//
17+
// Require absolute file path.
1718
type Cgo struct {
1819
goCacheDir string
1920
}

pkg/result/processors/diff.go

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ const envGolangciDiffProcessorPatch = "GOLANGCI_DIFF_PROCESSOR_PATCH"
1818

1919
var _ Processor = (*Diff)(nil)
2020

21+
// Diff filters issues based on options `new`, `new-from-rev`, etc.
22+
//
23+
// Uses `git`.
24+
// The paths inside the patch are relative to the path where git is run (the same location where golangci-lint is run).
25+
//
26+
// Warning: it doesn't use `path-prefix` option.
2127
type Diff struct {
2228
onlyNew bool
2329
fromRev string

pkg/result/processors/exclude.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
var _ Processor = (*Exclude)(nil)
1313

14+
// Exclude filters reports only based on regular expressions applied to the report text.
1415
type Exclude struct {
1516
name string
1617

pkg/result/processors/exclude_rules.go

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ type excludeRule struct {
1515
baseRule
1616
}
1717

18+
// ExcludeRules filters reports based on multiple criteria:
19+
// - linter names (string)
20+
// - file path (regular expressions)
21+
// - text (regular expressions)
22+
// - code source (regular expressions)
23+
//
24+
// It uses the shortest relative paths and `path-prefix` option.
1825
type ExcludeRules struct {
1926
name string
2027

pkg/result/processors/filename_unadjuster.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ type adjustMap struct {
2222
m map[string]posMapper
2323
}
2424

25-
// FilenameUnadjuster is needed because a lot of linters use `fset.Position(f.Pos())` to get filename.
26-
// And they return adjusted filename (e.g.` *.qtpl`) for an issue.
25+
// FilenameUnadjuster fixes filename based on adjusted and unadjusted position (related to line directives and cgo).
26+
//
27+
// A lot of linters use `fset.Position(f.Pos())` to get filename,
28+
// and they return adjusted filename (e.g.` *.qtpl`) for an issue.
2729
// We need restore real `.go` filename to properly output it, parse it, etc.
2830
//
29-
// Require absolute filepath.
31+
// Require absolute file path.
3032
type FilenameUnadjuster struct {
3133
m map[string]posMapper // map from adjusted filename to position mapper: adjusted -> unadjusted position
3234
log logutils.Log

pkg/result/processors/fixer.go

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ var _ Processor = (*Fixer)(nil)
3131

3232
const filePerm = 0644
3333

34+
// Fixer fixes reports if possible.
35+
// The reports that are not fixed are passed to the next processor.
3436
type Fixer struct {
3537
cfg *config.Config
3638
log logutils.Log

pkg/result/processors/identifier_marker.go

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ type replacePattern struct {
1313
repl string
1414
}
1515

16+
// IdentifierMarker modifies report text.
17+
// It must be before [Exclude] and [ExcludeRules]:
18+
// users configure exclusions based on the modified text.
1619
type IdentifierMarker struct {
1720
patterns map[string][]replacePattern
1821
}

pkg/result/processors/invalid_issue.go

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99

1010
var _ Processor = (*InvalidIssue)(nil)
1111

12+
// InvalidIssue filters invalid reports.
13+
// - non-go files (except `go.mod`)
14+
// - reports without file path
1215
type InvalidIssue struct {
1316
log logutils.Log
1417
}

pkg/result/processors/max_from_linter.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
var _ Processor = (*MaxFromLinter)(nil)
1010

11+
// MaxFromLinter limits the number of reports from the same linter.
1112
type MaxFromLinter struct {
1213
linterCounter map[string]int
1314
limit int
@@ -34,11 +35,6 @@ func (p *MaxFromLinter) Process(issues []result.Issue) ([]result.Issue, error) {
3435
}
3536

3637
return filterIssuesUnsafe(issues, func(issue *result.Issue) bool {
37-
if issue.SuggestedFixes != nil && p.cfg.Issues.NeedFix {
38-
// we need to fix all issues at once => we need to return all of them
39-
return true
40-
}
41-
4238
p.linterCounter[issue.FromLinter]++ // always inc for stat
4339

4440
return p.linterCounter[issue.FromLinter] <= p.limit

pkg/result/processors/max_per_file_from_linter.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
var _ Processor = (*MaxPerFileFromLinter)(nil)
99

10+
// MaxPerFileFromLinter limits the number of reports by file and by linter.
1011
type MaxPerFileFromLinter struct {
1112
fileLinterCounter fileLinterCounter
1213
maxPerFileFromLinterConfig map[string]int

pkg/result/processors/max_same_issues.go

+2-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
var _ Processor = (*MaxSameIssues)(nil)
1212

13+
// MaxSameIssues limits the number of reports with the same text.
1314
type MaxSameIssues struct {
1415
textCounter map[string]int
1516
limit int
@@ -36,12 +37,8 @@ func (p *MaxSameIssues) Process(issues []result.Issue) ([]result.Issue, error) {
3637
}
3738

3839
return filterIssuesUnsafe(issues, func(issue *result.Issue) bool {
39-
if issue.SuggestedFixes != nil && p.cfg.Issues.NeedFix {
40-
// we need to fix all issues at once => we need to return all of them
41-
return true
42-
}
43-
4440
p.textCounter[issue.Text]++ // always inc for stat
41+
4542
return p.textCounter[issue.Text] <= p.limit
4643
}), nil
4744
}

pkg/result/processors/nolint.go

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type fileData struct {
6464
ignoredRanges []ignoredRange
6565
}
6666

67+
// Nolint filters and sorts reports related to `nolint` directives.
6768
type Nolint struct {
6869
fileCache map[string]*fileData
6970
dbManager *lintersdb.Manager

pkg/result/processors/path_prefixer.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import (
77

88
var _ Processor = (*PathPrefixer)(nil)
99

10-
// PathPrefixer adds a customizable prefix to every output path
10+
// PathPrefixer adds a customizable path prefix to report file paths for user facing.
11+
// It uses the shortest relative paths and `path-prefix` option.
1112
type PathPrefixer struct {
1213
prefix string
1314
}
@@ -24,11 +25,14 @@ func (*PathPrefixer) Name() string {
2425

2526
// Process adds the prefix to each path
2627
func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) {
27-
if p.prefix != "" {
28-
for i := range issues {
29-
issues[i].Pos.Filename = fsutils.WithPathPrefix(p.prefix, issues[i].Pos.Filename)
30-
}
28+
if p.prefix == "" {
29+
return issues, nil
3130
}
31+
32+
for i := range issues {
33+
issues[i].Pos.Filename = fsutils.WithPathPrefix(p.prefix, issues[i].Pos.Filename)
34+
}
35+
3236
return issues, nil
3337
}
3438

pkg/result/processors/path_prettifier.go

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
var _ Processor = (*PathPrettifier)(nil)
1212

13+
// PathPrettifier modifies report file path with the shortest relative path.
1314
type PathPrettifier struct {
1415
log logutils.Log
1516
}

pkg/result/processors/path_shortener.go

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
var _ Processor = (*PathShortener)(nil)
1212

13+
// PathShortener modifies text of the reports to reduce file path inside the text.
14+
// It uses the rooted path name corresponding to the current directory (`wd`).
1315
type PathShortener struct {
1416
wd string
1517
}

pkg/result/processors/severity.go

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ type severityRule struct {
1919
severity string
2020
}
2121

22+
// Severity modifies report severity.
23+
// It uses the same `baseRule` structure as [ExcludeRules] processor.
24+
//
25+
// Warning: it doesn't use `path-prefix` option.
2226
type Severity struct {
2327
name string
2428

pkg/result/processors/skip_dirs.go

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ var StdExcludeDirRegexps = []string{
2121
normalizePathRegex("builtin"),
2222
}
2323

24+
// SkipDirs filters reports based on directory names.
25+
// It uses the shortest relative paths and `path-prefix` option.
2426
type skipStat struct {
2527
pattern string
2628
count int

pkg/result/processors/skip_files.go

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import (
1010

1111
var _ Processor = (*SkipFiles)(nil)
1212

13+
// SkipFiles filters reports based on filename.
14+
//
15+
// It uses the shortest relative paths and `path-prefix` option.
1316
type SkipFiles struct {
1417
patterns []*regexp.Regexp
1518
pathPrefix string

pkg/result/processors/sort_results.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ import (
1010
"github.com/golangci/golangci-lint/pkg/result"
1111
)
1212

13-
// Base propose of this functionality to sort results (issues)
14-
// produced by various linters by analyzing code. We're achieving this
15-
// by sorting results.Issues using processor step, and chain based
16-
// rules that can compare different properties of the Issues struct.
17-
1813
const (
1914
orderNameFile = "file"
2015
orderNameLinter = "linter"
@@ -31,6 +26,10 @@ var _ Processor = (*SortResults)(nil)
3126

3227
type issueComparator func(a, b *result.Issue) int
3328

29+
// SortResults sorts reports based on criteria:
30+
// - file names, line numbers, positions
31+
// - linter names
32+
// - severity names
3433
type SortResults struct {
3534
cmps map[string][]issueComparator
3635

pkg/result/processors/source_code.go

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ import (
88

99
var _ Processor = (*SourceCode)(nil)
1010

11+
// SourceCode modifies displayed information based on [result.Issue.GetLineRange()].
12+
//
13+
// This is used:
14+
// - to display the "UnderLinePointer".
15+
// - in some rare cases to display multiple lines instead of one (ex: `dupl`)
16+
//
17+
// It requires to use [fsutils.LineCache] ([fsutils.FileCache]) to get the file information before the fixes.
1118
type SourceCode struct {
1219
lineCache *fsutils.LineCache
1320
log logutils.Log

0 commit comments

Comments
 (0)