@@ -52,7 +52,7 @@ type Analyzer struct {
52
52
template string
53
53
}
54
54
55
- func (a * Analyzer ) Analyze (target * Target ) Issue {
55
+ func (a * Analyzer ) Analyze (target * Target ) ( i Issue ) {
56
56
if a .template == "" {
57
57
return NewIssue ("Missed template for check" )
58
58
}
@@ -74,6 +74,16 @@ func (a *Analyzer) Analyze(target *Target) Issue {
74
74
offset .Position += 3
75
75
}
76
76
}
77
+ defer func () {
78
+ if i .Message () == "" {
79
+ return
80
+ }
81
+ fix , ok := a .generateFix (i , file , header )
82
+ if ! ok {
83
+ return
84
+ }
85
+ i = NewIssueWithFix (i .Message (), i .Location (), fix )
86
+ }()
77
87
header = strings .TrimSpace (header )
78
88
if header == "" {
79
89
return NewIssue ("Missed header for check" )
@@ -144,3 +154,93 @@ func New(options ...Option) *Analyzer {
144
154
}
145
155
return a
146
156
}
157
+
158
+ func (a * Analyzer ) generateFix (i Issue , file * ast.File , header string ) (Fix , bool ) {
159
+ var expect string
160
+ t := NewReader (a .template )
161
+ for ! t .Done () {
162
+ ch := t .Peek ()
163
+ if ch == '{' {
164
+ f := a .values [a .readField (t )]
165
+ if f == nil {
166
+ return Fix {}, false
167
+ }
168
+ if f .Calculate (a .values ) != nil {
169
+ return Fix {}, false
170
+ }
171
+ expect += f .Get ()
172
+ continue
173
+ }
174
+
175
+ expect += string (ch )
176
+ t .Next ()
177
+ }
178
+
179
+ fix := Fix {Expected : strings .Split (expect , "\n " )}
180
+ if ! (len (file .Comments ) > 0 && file .Comments [0 ].Pos () < file .Package ) {
181
+ for i := range fix .Expected {
182
+ fix .Expected [i ] = "// " + fix .Expected [i ]
183
+ }
184
+ return fix , true
185
+ }
186
+
187
+ actual := file .Comments [0 ].List [0 ].Text
188
+ if ! strings .HasPrefix (actual , "/*" ) {
189
+ for i := range fix .Expected {
190
+ fix .Expected [i ] = "// " + fix .Expected [i ]
191
+ }
192
+ for _ , c := range file .Comments [0 ].List {
193
+ fix .Actual = append (fix .Actual , c .Text )
194
+ }
195
+ i = NewIssueWithFix (i .Message (), i .Location (), fix )
196
+ return fix , true
197
+ }
198
+
199
+ gets := func (i int , end bool ) string {
200
+ if i < 0 {
201
+ return header
202
+ }
203
+ if end {
204
+ return header [i + 1 :]
205
+ }
206
+ return header [:i ]
207
+ }
208
+ start := strings .Index (actual , gets (strings .IndexByte (header , '\n' ), false ))
209
+ if start < 0 {
210
+ return Fix {}, false // Should be impossible
211
+ }
212
+ nl := strings .LastIndexByte (actual [:start ], '\n' )
213
+ if nl >= 0 {
214
+ fix .Actual = strings .Split (actual [:nl ], "\n " )
215
+ fix .Expected = append (fix .Actual , fix .Expected ... )
216
+ actual = actual [nl + 1 :]
217
+ start -= nl + 1
218
+ }
219
+
220
+ prefix := actual [:start ]
221
+ if nl < 0 {
222
+ fix .Expected [0 ] = prefix + fix .Expected [0 ]
223
+ } else {
224
+ n := len (fix .Actual )
225
+ for i := range fix .Expected [n :] {
226
+ fix .Expected [n + i ] = prefix + fix .Expected [n + i ]
227
+ }
228
+ }
229
+
230
+ last := gets (strings .LastIndexByte (header , '\n' ), true )
231
+ end := strings .Index (actual , last )
232
+ if end < 0 {
233
+ return Fix {}, false // Should be impossible
234
+ }
235
+
236
+ trailing := actual [end + len (last ):]
237
+ if i := strings .IndexRune (trailing , '\n' ); i < 0 {
238
+ fix .Expected [len (fix .Expected )- 1 ] += trailing
239
+ } else {
240
+ fix .Expected [len (fix .Expected )- 1 ] += trailing [:i ]
241
+ fix .Expected = append (fix .Expected , strings .Split (trailing [i + 1 :], "\n " )... )
242
+ }
243
+
244
+ fix .Actual = append (fix .Actual , strings .Split (actual , "\n " )... )
245
+ return fix , true
246
+ }
0 commit comments