2
2
package internal
3
3
4
4
import (
5
- "fmt"
6
- "go/ast"
7
- "go/token"
8
5
"regexp"
9
6
"strings"
10
- "unicode"
11
7
8
+ "golang.org/x/tools/go/analysis"
9
+
10
+ "github.com/golangci/golangci-lint/pkg/goanalysis"
12
11
"github.com/golangci/golangci-lint/pkg/result"
13
12
)
14
13
15
- type BaseIssue struct {
16
- fullDirective string
17
- directiveWithOptionalLeadingSpace string
18
- position token.Position
19
- replacement * result.Replacement
20
- }
21
-
22
- //nolint:gocritic // TODO(ldez) must be change in the future.
23
- func (b BaseIssue ) Position () token.Position {
24
- return b .position
25
- }
26
-
27
- //nolint:gocritic // TODO(ldez) must be change in the future.
28
- func (b BaseIssue ) Replacement () * result.Replacement {
29
- return b .replacement
30
- }
31
-
32
- type ExtraLeadingSpace struct {
33
- BaseIssue
34
- }
35
-
36
- //nolint:gocritic // TODO(ldez) must be change in the future.
37
- func (i ExtraLeadingSpace ) Details () string {
38
- return fmt .Sprintf ("directive `%s` should not have more than one leading space" , i .fullDirective )
39
- }
40
-
41
- func (i ExtraLeadingSpace ) String () string { return toString (i ) }
42
-
43
- type NotMachine struct {
44
- BaseIssue
45
- }
46
-
47
- //nolint:gocritic // TODO(ldez) must be change in the future.
48
- func (i NotMachine ) Details () string {
49
- expected := i .fullDirective [:2 ] + strings .TrimLeftFunc (i .fullDirective [2 :], unicode .IsSpace )
50
- return fmt .Sprintf ("directive `%s` should be written without leading space as `%s`" ,
51
- i .fullDirective , expected )
52
- }
53
-
54
- func (i NotMachine ) String () string { return toString (i ) }
55
-
56
- type NotSpecific struct {
57
- BaseIssue
58
- }
59
-
60
- //nolint:gocritic // TODO(ldez) must be change in the future.
61
- func (i NotSpecific ) Details () string {
62
- return fmt .Sprintf ("directive `%s` should mention specific linter such as `%s:my-linter`" ,
63
- i .fullDirective , i .directiveWithOptionalLeadingSpace )
64
- }
65
-
66
- func (i NotSpecific ) String () string { return toString (i ) }
67
-
68
- type ParseError struct {
69
- BaseIssue
70
- }
71
-
72
- //nolint:gocritic // TODO(ldez) must be change in the future.
73
- func (i ParseError ) Details () string {
74
- return fmt .Sprintf ("directive `%s` should match `%s[:<comma-separated-linters>] [// <explanation>]`" ,
75
- i .fullDirective ,
76
- i .directiveWithOptionalLeadingSpace )
77
- }
78
-
79
- func (i ParseError ) String () string { return toString (i ) }
80
-
81
- type NoExplanation struct {
82
- BaseIssue
83
- fullDirectiveWithoutExplanation string
84
- }
85
-
86
- //nolint:gocritic // TODO(ldez) must be change in the future.
87
- func (i NoExplanation ) Details () string {
88
- return fmt .Sprintf ("directive `%s` should provide explanation such as `%s // this is why`" ,
89
- i .fullDirective , i .fullDirectiveWithoutExplanation )
90
- }
91
-
92
- func (i NoExplanation ) String () string { return toString (i ) }
93
-
94
- type UnusedCandidate struct {
95
- BaseIssue
96
- ExpectedLinter string
97
- }
98
-
99
- //nolint:gocritic // TODO(ldez) must be change in the future.
100
- func (i UnusedCandidate ) Details () string {
101
- details := fmt .Sprintf ("directive `%s` is unused" , i .fullDirective )
102
- if i .ExpectedLinter != "" {
103
- details += fmt .Sprintf (" for linter %q" , i .ExpectedLinter )
104
- }
105
- return details
106
- }
107
-
108
- func (i UnusedCandidate ) String () string { return toString (i ) }
109
-
110
- func toString (issue Issue ) string {
111
- return fmt .Sprintf ("%s at %s" , issue .Details (), issue .Position ())
112
- }
113
-
114
- type Issue interface {
115
- Details () string
116
- Position () token.Position
117
- String () string
118
- Replacement () * result.Replacement
119
- }
120
-
121
- type Needs uint
14
+ const LinterName = "nolintlint"
122
15
123
16
const (
124
17
NeedsMachineOnly Needs = 1 << iota
@@ -128,6 +21,8 @@ const (
128
21
NeedsAll = NeedsMachineOnly | NeedsSpecific | NeedsExplanation
129
22
)
130
23
24
+ type Needs uint
25
+
131
26
var commentPattern = regexp .MustCompile (`^//\s*(nolint)(:\s*[\w-]+\s*(?:,\s*[\w-]+\s*)*)?\b` )
132
27
133
28
// matches a complete nolint directive
@@ -157,15 +52,10 @@ var (
157
52
)
158
53
159
54
//nolint:funlen,gocyclo // the function is going to be refactored in the future
160
- func (l Linter ) Run (fset * token.FileSet , nodes ... ast.Node ) ([]Issue , error ) {
161
- var issues []Issue
162
-
163
- for _ , node := range nodes {
164
- file , ok := node .(* ast.File )
165
- if ! ok {
166
- continue
167
- }
55
+ func (l Linter ) Run (pass * analysis.Pass ) ([]goanalysis.Issue , error ) {
56
+ var issues []goanalysis.Issue
168
57
58
+ for _ , file := range pass .Files {
169
59
for _ , c := range file .Comments {
170
60
for _ , comment := range c .List {
171
61
if ! commentPattern .MatchString (comment .Text ) {
@@ -188,39 +78,51 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
188
78
split := strings .Split (strings .SplitN (comment .Text , ":" , 2 )[0 ], "//" )
189
79
directiveWithOptionalLeadingSpace += strings .TrimSpace (split [1 ])
190
80
191
- pos := fset .Position (comment .Pos ())
192
- end := fset .Position (comment .End ())
193
-
194
- base := BaseIssue {
195
- fullDirective : comment .Text ,
196
- directiveWithOptionalLeadingSpace : directiveWithOptionalLeadingSpace ,
197
- position : pos ,
198
- }
81
+ pos := pass .Fset .Position (comment .Pos ())
82
+ end := pass .Fset .Position (comment .End ())
199
83
200
84
// check for, report and eliminate leading spaces, so we can check for other issues
201
85
if leadingSpace != "" {
202
86
removeWhitespace := & result.Replacement {
203
87
Inline : & result.InlineFix {
204
- StartCol : pos .Column + 1 ,
205
- Length : len (leadingSpace ),
206
- NewString : "" ,
88
+ StartCol : pos .Column + 1 ,
89
+ Length : len (leadingSpace ),
207
90
},
208
91
}
92
+
209
93
if (l .needs & NeedsMachineOnly ) != 0 {
210
- issue := NotMachine {BaseIssue : base }
211
- issue .BaseIssue .replacement = removeWhitespace
212
- issues = append (issues , issue )
94
+ issue := & result.Issue {
95
+ FromLinter : LinterName ,
96
+ Text : formatNotMachine (comment .Text ),
97
+ Pos : pos ,
98
+ Replacement : removeWhitespace ,
99
+ }
100
+
101
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
213
102
} else if len (leadingSpace ) > 1 {
214
- issue := ExtraLeadingSpace {BaseIssue : base }
215
- issue .BaseIssue .replacement = removeWhitespace
216
- issue .BaseIssue .replacement .Inline .NewString = " " // assume a single space was intended
217
- issues = append (issues , issue )
103
+ issue := & result.Issue {
104
+ FromLinter : LinterName ,
105
+ Text : formatExtraLeadingSpace (comment .Text ),
106
+ Pos : pos ,
107
+ Replacement : removeWhitespace ,
108
+ }
109
+
110
+ issue .Replacement .Inline .NewString = " " // assume a single space was intended
111
+
112
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
218
113
}
219
114
}
220
115
221
116
fullMatches := fullDirectivePattern .FindStringSubmatch (comment .Text )
222
117
if len (fullMatches ) == 0 {
223
- issues = append (issues , ParseError {BaseIssue : base })
118
+ issue := & result.Issue {
119
+ FromLinter : LinterName ,
120
+ Text : formatParseError (comment .Text , directiveWithOptionalLeadingSpace ),
121
+ Pos : pos ,
122
+ }
123
+
124
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
125
+
224
126
continue
225
127
}
226
128
@@ -246,7 +148,13 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
246
148
247
149
if (l .needs & NeedsSpecific ) != 0 {
248
150
if len (linters ) == 0 {
249
- issues = append (issues , NotSpecific {BaseIssue : base })
151
+ issue := & result.Issue {
152
+ FromLinter : LinterName ,
153
+ Text : formatNotSpecific (comment .Text , directiveWithOptionalLeadingSpace ),
154
+ Pos : pos ,
155
+ }
156
+
157
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
250
158
}
251
159
}
252
160
@@ -261,26 +169,39 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
261
169
removeNolintCompletely .NeedOnlyDelete = true
262
170
} else {
263
171
removeNolintCompletely .Inline = & result.InlineFix {
264
- StartCol : startCol ,
265
- Length : end .Column - pos .Column ,
266
- NewString : "" ,
172
+ StartCol : startCol ,
173
+ Length : end .Column - pos .Column ,
267
174
}
268
175
}
269
176
270
177
if len (linters ) == 0 {
271
- issue := UnusedCandidate {BaseIssue : base }
272
- issue .replacement = removeNolintCompletely
273
- issues = append (issues , issue )
178
+ issue := & result.Issue {
179
+ FromLinter : LinterName ,
180
+ Text : formatUnusedCandidate (comment .Text , "" ),
181
+ Pos : pos ,
182
+ ExpectNoLint : true ,
183
+ Replacement : removeNolintCompletely ,
184
+ }
185
+
186
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
274
187
} else {
275
188
for _ , linter := range linters {
276
- issue := UnusedCandidate {BaseIssue : base , ExpectedLinter : linter }
189
+ issue := & result.Issue {
190
+ FromLinter : LinterName ,
191
+ Text : formatUnusedCandidate (comment .Text , linter ),
192
+ Pos : pos ,
193
+ ExpectNoLint : true ,
194
+ ExpectedNoLintLinter : linter ,
195
+ }
196
+
277
197
// only offer replacement if there is a single linter
278
198
// because of issues around commas and the possibility of all
279
199
// linters being removed
280
200
if len (linters ) == 1 {
281
- issue .replacement = removeNolintCompletely
201
+ issue .Replacement = removeNolintCompletely
282
202
}
283
- issues = append (issues , issue )
203
+
204
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
284
205
}
285
206
}
286
207
}
@@ -297,10 +218,14 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
297
218
298
219
if needsExplanation {
299
220
fullDirectiveWithoutExplanation := trailingBlankExplanation .ReplaceAllString (comment .Text , "" )
300
- issues = append (issues , NoExplanation {
301
- BaseIssue : base ,
302
- fullDirectiveWithoutExplanation : fullDirectiveWithoutExplanation ,
303
- })
221
+
222
+ issue := & result.Issue {
223
+ FromLinter : LinterName ,
224
+ Text : formatNoExplanation (comment .Text , fullDirectiveWithoutExplanation ),
225
+ Pos : pos ,
226
+ }
227
+
228
+ issues = append (issues , goanalysis .NewIssue (issue , pass ))
304
229
}
305
230
}
306
231
}
0 commit comments