@@ -3,20 +3,23 @@ package internal
3
3
import (
4
4
"bytes"
5
5
"fmt"
6
+ "go/ast"
6
7
"go/token"
8
+ "slices"
7
9
"strings"
8
10
9
11
diffpkg "github.com/sourcegraph/go-diff/diff"
12
+ "golang.org/x/tools/go/analysis"
10
13
11
14
"github.com/golangci/golangci-lint/pkg/config"
15
+ "github.com/golangci/golangci-lint/pkg/goanalysis"
12
16
"github.com/golangci/golangci-lint/pkg/lint/linter"
13
17
"github.com/golangci/golangci-lint/pkg/logutils"
14
- "github.com/golangci/golangci-lint/pkg/result"
15
18
)
16
19
17
20
type Change struct {
18
- LineRange result. Range
19
- Replacement result. Replacement
21
+ From , To int
22
+ NewLines [] string
20
23
}
21
24
22
25
type diffLineType string
@@ -44,58 +47,48 @@ type hunkChangesParser struct {
44
47
45
48
log logutils.Log
46
49
47
- lines []diffLine
48
-
49
- ret []Change
50
+ changes []Change
50
51
}
51
52
52
- func (p * hunkChangesParser ) parseDiffLines (h * diffpkg.Hunk ) {
53
- lines := bytes .Split (h .Body , []byte {'\n' })
54
- currentOriginalLineNumber := int (h .OrigStartLine )
55
- var ret []diffLine
53
+ func (p * hunkChangesParser ) parse (h * diffpkg.Hunk ) []Change {
54
+ lines := parseDiffLines (h )
56
55
57
- for i , line := range lines {
58
- dl := diffLine {
59
- originalNumber : currentOriginalLineNumber ,
56
+ for i := 0 ; i < len (lines ); {
57
+ line := lines [i ]
58
+
59
+ if line .typ == diffLineOriginal {
60
+ p .handleOriginalLine (lines , line , & i )
61
+ continue
60
62
}
61
63
62
- lineStr := string (line )
64
+ var deletedLines []diffLine
65
+ for ; i < len (lines ) && lines [i ].typ == diffLineDeleted ; i ++ {
66
+ deletedLines = append (deletedLines , lines [i ])
67
+ }
63
68
64
- if strings .HasPrefix (lineStr , "-" ) {
65
- dl .typ = diffLineDeleted
66
- dl .data = strings .TrimPrefix (lineStr , "-" )
67
- currentOriginalLineNumber ++
68
- } else if strings .HasPrefix (lineStr , "+" ) {
69
- dl .typ = diffLineAdded
70
- dl .data = strings .TrimPrefix (lineStr , "+" )
71
- } else {
72
- if i == len (lines )- 1 && lineStr == "" {
73
- // handle last \n: don't add an empty original line
74
- break
75
- }
69
+ var addedLines []string
70
+ for ; i < len (lines ) && lines [i ].typ == diffLineAdded ; i ++ {
71
+ addedLines = append (addedLines , lines [i ].data )
72
+ }
76
73
77
- dl . typ = diffLineOriginal
78
- dl . data = strings . TrimPrefix ( lineStr , " " )
79
- currentOriginalLineNumber ++
74
+ if len ( deletedLines ) != 0 {
75
+ p . handleDeletedLines ( deletedLines , addedLines )
76
+ continue
80
77
}
81
78
82
- ret = append (ret , dl )
79
+ // no deletions, only additions
80
+ p .handleAddedOnlyLines (addedLines )
83
81
}
84
82
85
- // if > 0, then the original file had a 'No newline at end of file' mark
86
- if h .OrigNoNewlineAt > 0 {
87
- dl := diffLine {
88
- originalNumber : currentOriginalLineNumber + 1 ,
89
- typ : diffLineAdded ,
90
- data : "" ,
91
- }
92
- ret = append (ret , dl )
83
+ if len (p .replacementLinesToPrepend ) != 0 {
84
+ p .log .Infof ("The diff contains only additions: no original or deleted lines: %#v" , lines )
85
+ return nil
93
86
}
94
87
95
- p . lines = ret
88
+ return p . changes
96
89
}
97
90
98
- func (p * hunkChangesParser ) handleOriginalLine (line diffLine , i * int ) {
91
+ func (p * hunkChangesParser ) handleOriginalLine (lines [] diffLine , line diffLine , i * int ) {
99
92
if len (p .replacementLinesToPrepend ) == 0 {
100
93
p .lastOriginalLine = & line
101
94
* i ++
@@ -109,51 +102,39 @@ func (p *hunkChangesParser) handleOriginalLine(line diffLine, i *int) {
109
102
110
103
* i ++
111
104
var followingAddedLines []string
112
- for ; * i < len (p .lines ) && p .lines [* i ].typ == diffLineAdded ; * i ++ {
113
- followingAddedLines = append (followingAddedLines , p .lines [* i ].data )
105
+ for ; * i < len (lines ) && lines [* i ].typ == diffLineAdded ; * i ++ {
106
+ followingAddedLines = append (followingAddedLines , lines [* i ].data )
107
+ }
108
+
109
+ change := Change {
110
+ From : line .originalNumber ,
111
+ To : line .originalNumber ,
112
+ NewLines : slices .Concat (p .replacementLinesToPrepend , []string {line .data }, followingAddedLines ),
114
113
}
114
+ p .changes = append (p .changes , change )
115
115
116
- p .ret = append (p .ret , Change {
117
- LineRange : result.Range {
118
- From : line .originalNumber ,
119
- To : line .originalNumber ,
120
- },
121
- Replacement : result.Replacement {
122
- NewLines : append (p .replacementLinesToPrepend , append ([]string {line .data }, followingAddedLines ... )... ),
123
- },
124
- })
125
116
p .replacementLinesToPrepend = nil
126
117
p .lastOriginalLine = & line
127
118
}
128
119
129
120
func (p * hunkChangesParser ) handleDeletedLines (deletedLines []diffLine , addedLines []string ) {
130
121
change := Change {
131
- LineRange : result.Range {
132
- From : deletedLines [0 ].originalNumber ,
133
- To : deletedLines [len (deletedLines )- 1 ].originalNumber ,
134
- },
122
+ From : deletedLines [0 ].originalNumber ,
123
+ To : deletedLines [len (deletedLines )- 1 ].originalNumber ,
135
124
}
136
125
137
- if len (addedLines ) != 0 {
138
- change .Replacement .NewLines = append ([]string {}, p .replacementLinesToPrepend ... )
139
- change .Replacement .NewLines = append (change .Replacement .NewLines , addedLines ... )
140
- if len (p .replacementLinesToPrepend ) != 0 {
141
- p .replacementLinesToPrepend = nil
142
- }
143
-
144
- p .ret = append (p .ret , change )
145
- return
146
- }
126
+ switch {
127
+ case len (addedLines ) != 0 :
128
+ change .NewLines = slices .Concat (p .replacementLinesToPrepend , addedLines )
129
+ p .replacementLinesToPrepend = nil
147
130
148
- // delete-only change with possible prepending
149
- if len ( p . replacementLinesToPrepend ) != 0 {
150
- change .Replacement . NewLines = p .replacementLinesToPrepend
131
+ case len ( p . replacementLinesToPrepend ) != 0 :
132
+ // delete-only change with possible prepending
133
+ change .NewLines = slices . Clone ( p .replacementLinesToPrepend )
151
134
p .replacementLinesToPrepend = nil
152
- } else {
153
- change .Replacement .NeedOnlyDelete = true
154
135
}
155
136
156
- p .ret = append (p .ret , change )
137
+ p .changes = append (p .changes , change )
157
138
}
158
139
159
140
func (p * hunkChangesParser ) handleAddedOnlyLines (addedLines []string ) {
@@ -166,70 +147,88 @@ func (p *hunkChangesParser) handleAddedOnlyLines(addedLines []string) {
166
147
// 2. ...
167
148
168
149
p .replacementLinesToPrepend = addedLines
150
+
169
151
return
170
152
}
171
153
172
154
// add-only change merged into the last original line with possible prepending
173
- p .ret = append (p .ret , Change {
174
- LineRange : result.Range {
175
- From : p .lastOriginalLine .originalNumber ,
176
- To : p .lastOriginalLine .originalNumber ,
177
- },
178
- Replacement : result.Replacement {
179
- NewLines : append (p .replacementLinesToPrepend , append ([]string {p .lastOriginalLine .data }, addedLines ... )... ),
180
- },
181
- })
155
+ change := Change {
156
+ From : p .lastOriginalLine .originalNumber ,
157
+ To : p .lastOriginalLine .originalNumber ,
158
+ NewLines : slices .Concat (p .replacementLinesToPrepend , []string {p .lastOriginalLine .data }, addedLines ),
159
+ }
160
+
161
+ p .changes = append (p .changes , change )
162
+
182
163
p .replacementLinesToPrepend = nil
183
164
}
184
165
185
- func ( p * hunkChangesParser ) parse ( h * diffpkg.Hunk ) []Change {
186
- p . parseDiffLines ( h )
166
+ func parseDiffLines ( h * diffpkg.Hunk ) []diffLine {
167
+ lines := bytes . Split ( h . Body , [] byte { '\n' } )
187
168
188
- for i := 0 ; i < len (p .lines ); {
189
- line := p .lines [i ]
190
- if line .typ == diffLineOriginal {
191
- p .handleOriginalLine (line , & i )
192
- continue
193
- }
169
+ currentOriginalLineNumber := int (h .OrigStartLine )
194
170
195
- var deletedLines []diffLine
196
- for ; i < len (p .lines ) && p .lines [i ].typ == diffLineDeleted ; i ++ {
197
- deletedLines = append (deletedLines , p .lines [i ])
171
+ var diffLines []diffLine
172
+
173
+ for i , line := range lines {
174
+ dl := diffLine {
175
+ originalNumber : currentOriginalLineNumber ,
198
176
}
199
177
200
- var addedLines [] string
201
- for ; i < len ( p . lines ) && p . lines [ i ]. typ == diffLineAdded ; i ++ {
202
- addedLines = append ( addedLines , p . lines [ i ]. data )
178
+ if i == len ( lines ) - 1 && len ( line ) == 0 {
179
+ // handle last \n: don't add an empty original line
180
+ break
203
181
}
204
182
205
- if len (deletedLines ) != 0 {
206
- p .handleDeletedLines (deletedLines , addedLines )
207
- continue
183
+ lineStr := string (line )
184
+
185
+ switch {
186
+ case strings .HasPrefix (lineStr , "-" ):
187
+ dl .typ = diffLineDeleted
188
+ dl .data = strings .TrimPrefix (lineStr , "-" )
189
+ currentOriginalLineNumber ++
190
+
191
+ case strings .HasPrefix (lineStr , "+" ):
192
+ dl .typ = diffLineAdded
193
+ dl .data = strings .TrimPrefix (lineStr , "+" )
194
+
195
+ default :
196
+ dl .typ = diffLineOriginal
197
+ dl .data = strings .TrimPrefix (lineStr , " " )
198
+ currentOriginalLineNumber ++
208
199
}
209
200
210
- // no deletions, only additions
211
- p .handleAddedOnlyLines (addedLines )
201
+ diffLines = append (diffLines , dl )
212
202
}
213
203
214
- if len (p .replacementLinesToPrepend ) != 0 {
215
- p .log .Infof ("The diff contains only additions: no original or deleted lines: %#v" , p .lines )
216
- return nil
204
+ // if > 0, then the original file had a 'No newline at end of file' mark
205
+ if h .OrigNoNewlineAt > 0 {
206
+ dl := diffLine {
207
+ originalNumber : currentOriginalLineNumber + 1 ,
208
+ typ : diffLineAdded ,
209
+ data : "" ,
210
+ }
211
+ diffLines = append (diffLines , dl )
217
212
}
218
213
219
- return p . ret
214
+ return diffLines
220
215
}
221
216
222
- func ExtractIssuesFromPatch (patch string , lintCtx * linter.Context , linterName string , formatter fmtTextFormatter ) ([]result.Issue , error ) {
217
+ func ExtractDiagnosticFromPatch (pass * analysis.Pass , file * ast.File , patch string ,
218
+ lintCtx * linter.Context , formatter fmtTextFormatter ) error {
223
219
diffs , err := diffpkg .ParseMultiFileDiff ([]byte (patch ))
224
220
if err != nil {
225
- return nil , fmt .Errorf ("can't parse patch: %w" , err )
221
+ return fmt .Errorf ("can't parse patch: %w" , err )
226
222
}
227
223
228
224
if len (diffs ) == 0 {
229
- return nil , fmt .Errorf ("got no diffs from patch parser: %v" , patch )
225
+ return fmt .Errorf ("got no diffs from patch parser: %v" , patch )
230
226
}
231
227
232
- var issues []result.Issue
228
+ ft := pass .Fset .File (file .Pos ())
229
+
230
+ adjLine := pass .Fset .PositionFor (file .Pos (), false ).Line - pass .Fset .PositionFor (file .Pos (), true ).Line
231
+
233
232
for _ , d := range diffs {
234
233
if len (d .Hunks ) == 0 {
235
234
lintCtx .Log .Warnf ("Got no hunks in diff %+v" , d )
@@ -242,23 +241,29 @@ func ExtractIssuesFromPatch(patch string, lintCtx *linter.Context, linterName st
242
241
changes := p .parse (hunk )
243
242
244
243
for _ , change := range changes {
245
- i := result.Issue {
246
- FromLinter : linterName ,
247
- Pos : token.Position {
248
- Filename : d .NewName ,
249
- Line : change .LineRange .From ,
250
- },
251
- Text : formatter (lintCtx .Settings ()),
252
- Replacement : & change .Replacement ,
253
- }
254
- if change .LineRange .From != change .LineRange .To {
255
- i .LineRange = & change .LineRange
256
- }
257
-
258
- issues = append (issues , i )
244
+ pass .Report (toDiagnostic (ft , change , formatter (lintCtx .Settings ()), adjLine ))
259
245
}
260
246
}
261
247
}
262
248
263
- return issues , nil
249
+ return nil
250
+ }
251
+
252
+ func toDiagnostic (ft * token.File , change Change , message string , adjLine int ) analysis.Diagnostic {
253
+ start := ft .LineStart (change .From + adjLine )
254
+
255
+ end := goanalysis .EndOfLinePos (ft , change .To + adjLine )
256
+
257
+ return analysis.Diagnostic {
258
+ Pos : start ,
259
+ End : end ,
260
+ Message : message , // TODO(ldez) change message formatter to have a better message.
261
+ SuggestedFixes : []analysis.SuggestedFix {{
262
+ TextEdits : []analysis.TextEdit {{
263
+ Pos : start ,
264
+ End : end ,
265
+ NewText : []byte (strings .Join (change .NewLines , "\n " )),
266
+ }},
267
+ }},
268
+ }
264
269
}
0 commit comments