@@ -65,23 +65,37 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
65
65
})
66
66
}
67
67
case source .Go :
68
- edits , editsPerFix , err := source .AllImportsFixes (ctx , snapshot , fh )
69
- if err != nil {
70
- return nil , err
68
+ diagnostics := params .Context .Diagnostics
69
+
70
+ var importEdits []protocol.TextEdit
71
+ var importEditsPerFix []* source.ImportFix
72
+ var analysisQuickFixes []protocol.CodeAction
73
+ var highConfidenceEdits []protocol.TextDocumentEdit
74
+
75
+ // Retrieve any necessary import edits or fixes.
76
+ if wanted [protocol .QuickFix ] && len (diagnostics ) > 0 || wanted [protocol .SourceOrganizeImports ] {
77
+ importEdits , importEditsPerFix , err = source .AllImportsFixes (ctx , snapshot , fh )
78
+ if err != nil {
79
+ return nil , err
80
+ }
71
81
}
72
- if diagnostics := params . Context . Diagnostics ; wanted [ protocol . QuickFix ] && len ( diagnostics ) > 0 {
73
- // First, add the quick fixes reported by go/analysis.
74
- qf , err := quickFixes (ctx , snapshot , fh , diagnostics )
82
+ // Retrieve any necessary analysis fixes or edits.
83
+ if ( wanted [ protocol . QuickFix ] || wanted [ protocol . SourceFixAll ]) && len ( diagnostics ) > 0 {
84
+ analysisQuickFixes , highConfidenceEdits , err = analysisFixes (ctx , snapshot , fh , diagnostics )
75
85
if err != nil {
76
- event .Error (ctx , "quick fixes failed" , err , tag .URI .Of (uri ))
86
+ event .Error (ctx , "analysis fixes failed" , err , tag .URI .Of (uri ))
77
87
}
78
- codeActions = append (codeActions , qf ... )
88
+ }
89
+
90
+ if wanted [protocol .QuickFix ] && len (diagnostics ) > 0 {
91
+ // First, add the quick fixes reported by go/analysis.
92
+ codeActions = append (codeActions , analysisQuickFixes ... )
79
93
80
94
// If we also have diagnostics for missing imports, we can associate them with quick fixes.
81
95
if findImportErrors (diagnostics ) {
82
96
// Separate this into a set of codeActions per diagnostic, where
83
97
// each action is the addition, removal, or renaming of one import.
84
- for _ , importFix := range editsPerFix {
98
+ for _ , importFix := range importEditsPerFix {
85
99
// Get the diagnostics this fix would affect.
86
100
if fixDiagnostics := importDiagnostics (importFix .Fix , diagnostics ); len (fixDiagnostics ) > 0 {
87
101
codeActions = append (codeActions , protocol.CodeAction {
@@ -95,6 +109,8 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
95
109
}
96
110
}
97
111
}
112
+
113
+ // Get any actions that might be attributed to missing modules in the go.mod file.
98
114
actions , err := mod .SuggestedGoFixes (ctx , snapshot , fh , diagnostics )
99
115
if err != nil {
100
116
event .Error (ctx , "quick fixes failed" , err , tag .URI .Of (uri ))
@@ -103,12 +119,21 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
103
119
codeActions = append (codeActions , actions ... )
104
120
}
105
121
}
106
- if wanted [protocol .SourceOrganizeImports ] && len (edits ) > 0 {
122
+ if wanted [protocol .SourceOrganizeImports ] && len (importEdits ) > 0 {
107
123
codeActions = append (codeActions , protocol.CodeAction {
108
124
Title : "Organize Imports" ,
109
125
Kind : protocol .SourceOrganizeImports ,
110
126
Edit : protocol.WorkspaceEdit {
111
- DocumentChanges : documentChanges (fh , edits ),
127
+ DocumentChanges : documentChanges (fh , importEdits ),
128
+ },
129
+ })
130
+ }
131
+ if wanted [protocol .SourceFixAll ] && len (highConfidenceEdits ) > 0 {
132
+ codeActions = append (codeActions , protocol.CodeAction {
133
+ Title : "Simplifications" ,
134
+ Kind : protocol .SourceFixAll ,
135
+ Edit : protocol.WorkspaceEdit {
136
+ DocumentChanges : highConfidenceEdits ,
112
137
},
113
138
})
114
139
}
@@ -199,23 +224,28 @@ func importDiagnostics(fix *imports.ImportFix, diagnostics []protocol.Diagnostic
199
224
return results
200
225
}
201
226
202
- func quickFixes (ctx context.Context , snapshot source.Snapshot , fh source.FileHandle , diagnostics []protocol.Diagnostic ) ([]protocol.CodeAction , error ) {
227
+ func analysisFixes (ctx context.Context , snapshot source.Snapshot , fh source.FileHandle , diagnostics []protocol.Diagnostic ) ([]protocol.CodeAction , []protocol.TextDocumentEdit , error ) {
228
+ if len (diagnostics ) == 0 {
229
+ return nil , nil , nil
230
+ }
231
+
203
232
var codeActions []protocol.CodeAction
233
+ var sourceFixAllEdits []protocol.TextDocumentEdit
204
234
205
235
phs , err := snapshot .PackageHandles (ctx , fh )
206
236
if err != nil {
207
- return nil , err
237
+ return nil , nil , err
208
238
}
209
239
// We get the package that source.Diagnostics would've used. This is hack.
210
240
// TODO(golang/go#32443): The correct solution will be to cache diagnostics per-file per-snapshot.
211
241
ph , err := source .WidestPackageHandle (phs )
212
242
if err != nil {
213
- return nil , err
243
+ return nil , nil , err
214
244
}
215
245
for _ , diag := range diagnostics {
216
246
// This code assumes that the analyzer name is the Source of the diagnostic.
217
247
// If this ever changes, this will need to be addressed.
218
- srcErr , err := snapshot .FindAnalysisError (ctx , ph .ID (), diag .Source , diag .Message , diag .Range )
248
+ srcErr , analyzer , err := snapshot .FindAnalysisError (ctx , ph .ID (), diag .Source , diag .Message , diag .Range )
219
249
if err != nil {
220
250
continue
221
251
}
@@ -232,12 +262,16 @@ func quickFixes(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
232
262
event .Error (ctx , "no file" , err , tag .URI .Of (uri ))
233
263
continue
234
264
}
235
- action .Edit .DocumentChanges = append (action .Edit .DocumentChanges , documentChanges (fh , edits )... )
265
+ docChanges := documentChanges (fh , edits )
266
+ if analyzer .HighConfidence {
267
+ sourceFixAllEdits = append (sourceFixAllEdits , docChanges ... )
268
+ }
269
+ action .Edit .DocumentChanges = append (action .Edit .DocumentChanges , docChanges ... )
236
270
}
237
271
codeActions = append (codeActions , action )
238
272
}
239
273
}
240
- return codeActions , nil
274
+ return codeActions , sourceFixAllEdits , nil
241
275
}
242
276
243
277
func documentChanges (fh source.FileHandle , edits []protocol.TextEdit ) []protocol.TextDocumentEdit {
0 commit comments