diff --git a/pkg/golinters/goheader/goheader.go b/pkg/golinters/goheader/goheader.go index 49280365142a..63a45d46fae2 100644 --- a/pkg/golinters/goheader/goheader.go +++ b/pkg/golinters/goheader/goheader.go @@ -65,6 +65,10 @@ func runGoHeader(pass *analysis.Pass, conf *goheader.Configuration) error { for _, file := range pass.Files { position := goanalysis.GetFilePosition(pass, file) + if !strings.HasSuffix(position.Filename, ".go") { + continue + } + issue := a.Analyze(&goheader.Target{File: file, Path: position.Filename}) if issue == nil { continue @@ -72,24 +76,45 @@ func runGoHeader(pass *analysis.Pass, conf *goheader.Configuration) error { f := pass.Fset.File(file.Pos()) - start := f.LineStart(issue.Location().Line + 1) + commentLine := 1 + var offset int + + // Inspired by https://github.com/denis-tingaikin/go-header/blob/4c75a6a2332f025705325d6c71fff4616aedf48f/analyzer.go#L85-L92 + if len(file.Comments) > 0 && file.Comments[0].Pos() < file.Package { + if !strings.HasPrefix(file.Comments[0].List[0].Text, "/*") { + // When the comment are "//" there is a one character offset. + offset = 1 + } + commentLine = goanalysis.GetFilePositionFor(pass.Fset, file.Comments[0].Pos()).Line + } diag := analysis.Diagnostic{ - Pos: start, + Pos: f.LineStart(issue.Location().Line+1) + token.Pos(issue.Location().Position-offset), // The position of the first divergence. Message: issue.Message(), } if fix := issue.Fix(); fix != nil { - end := len(fix.Actual) + current := len(fix.Actual) for _, s := range fix.Actual { - end += len(s) + current += len(s) + } + + start := f.LineStart(commentLine) + + end := start + token.Pos(current) + + header := strings.Join(fix.Expected, "\n") + "\n" + + // Adds an extra line between the package and the header. + if end == file.Package { + header += "\n" } diag.SuggestedFixes = []analysis.SuggestedFix{{ TextEdits: []analysis.TextEdit{{ Pos: start, - End: start + token.Pos(end), - NewText: []byte(strings.Join(fix.Expected, "\n") + "\n"), + End: end, + NewText: []byte(header), }}, }} } diff --git a/pkg/golinters/goheader/testdata/fix/in/goheader_4.go b/pkg/golinters/goheader/testdata/fix/in/goheader_4.go new file mode 100644 index 000000000000..4513bacc661d --- /dev/null +++ b/pkg/golinters/goheader/testdata/fix/in/goheader_4.go @@ -0,0 +1,10 @@ +/* + Copyright 2024 The Awesome Project Authors + + Use of this source code is governed by LICENSE.md +*/ + +//golangcitest:args -Egoheader +//golangcitest:expected_exitcode 0 +//golangcitest:config_path testdata/goheader-fix.yml +package p diff --git a/pkg/golinters/goheader/testdata/fix/out/goheader_4.go b/pkg/golinters/goheader/testdata/fix/out/goheader_4.go new file mode 100644 index 000000000000..d0e6f8a8ef16 --- /dev/null +++ b/pkg/golinters/goheader/testdata/fix/out/goheader_4.go @@ -0,0 +1,10 @@ +/* + Copyright 2024 The Awesome Project Authors + + Use of this source code is governed by LICENSE +*/ + +//golangcitest:args -Egoheader +//golangcitest:expected_exitcode 0 +//golangcitest:config_path testdata/goheader-fix.yml +package p diff --git a/pkg/result/processors/fixer.go b/pkg/result/processors/fixer.go index ccab513cfea7..67b603a09bc0 100644 --- a/pkg/result/processors/fixer.go +++ b/pkg/result/processors/fixer.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "go/format" - "go/token" "os" "slices" @@ -77,7 +76,7 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) { for i := range issues { issue := issues[i] - if issue.SuggestedFixes == nil || skipTextEditWithoutPosition(&issue) { + if issue.SuggestedFixes == nil || skipNoTextEdit(&issue) { notFixableIssues = append(notFixableIssues, issue) continue } @@ -197,19 +196,15 @@ func (p Fixer) printStat() { p.sw.PrintStages() } -func skipTextEditWithoutPosition(issue *result.Issue) bool { +func skipNoTextEdit(issue *result.Issue) bool { var onlyMessage int - var count int for _, sf := range issue.SuggestedFixes { - for _, edit := range sf.TextEdits { - count++ - if edit.Pos == token.NoPos && edit.End == token.NoPos { - onlyMessage++ - } + if len(sf.TextEdits) == 0 { + onlyMessage++ } } - return count == onlyMessage + return len(issue.SuggestedFixes) == onlyMessage } // validateEdits returns a list of edits that is sorted and