-
Notifications
You must be signed in to change notification settings - Fork 4k
/
CodeFixContext.cs
256 lines (224 loc) · 10.7 KB
/
CodeFixContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeFixes
{
/// <summary>
/// Context for code fixes provided by a <see cref="CodeFixProvider"/>.
/// </summary>
public struct CodeFixContext : ITypeScriptCodeFixContext
{
private readonly Document _document;
private readonly Project _project;
private readonly TextSpan _span;
private readonly ImmutableArray<Diagnostic> _diagnostics;
private readonly CancellationToken _cancellationToken;
private readonly Action<CodeAction, ImmutableArray<Diagnostic>> _registerCodeFix;
/// <summary>
/// Document corresponding to the <see cref="CodeFixContext.Span"/> to fix.
/// </summary>
public Document Document => _document;
/// <summary>
/// Project corresponding to the diagnostics to fix.
/// </summary>
internal Project Project => _project;
/// <summary>
/// Text span within the <see cref="CodeFixContext.Document"/> to fix.
/// </summary>
public TextSpan Span => _span;
/// <summary>
/// Diagnostics to fix.
/// NOTE: All the diagnostics in this collection have the same <see cref="CodeFixContext.Span"/>.
/// </summary>
public ImmutableArray<Diagnostic> Diagnostics => _diagnostics;
/// <summary>
/// CancellationToken.
/// </summary>
public CancellationToken CancellationToken => _cancellationToken;
private readonly bool _isBlocking;
bool ITypeScriptCodeFixContext.IsBlocking => _isBlocking;
/// <summary>
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.RegisterCodeFixesAsync(CodeFixContext)"/> method.
/// </summary>
/// <param name="document">Document to fix.</param>
/// <param name="span">Text span within the <paramref name="document"/> to fix.</param>
/// <param name="diagnostics">
/// Diagnostics to fix.
/// All the diagnostics must have the same <paramref name="span"/>.
/// Additionally, the <see cref="Diagnostic.Id"/> of each diagnostic must be in the set of the <see cref="CodeFixProvider.FixableDiagnosticIds"/> of the associated <see cref="CodeFixProvider"/>.
/// </param>
/// <param name="registerCodeFix">Delegate to register a <see cref="CodeAction"/> fixing a subset of diagnostics.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <exception cref="ArgumentNullException">Throws this exception if any of the arguments is null.</exception>
/// <exception cref="ArgumentException">
/// Throws this exception if the given <paramref name="diagnostics"/> is empty,
/// has a null element or has an element whose span is not equal to <paramref name="span"/>.
/// </exception>
public CodeFixContext(
Document document,
TextSpan span,
ImmutableArray<Diagnostic> diagnostics,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
CancellationToken cancellationToken)
: this(document, span, diagnostics, registerCodeFix, verifyArguments: true, cancellationToken: cancellationToken)
{
}
/// <summary>
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.RegisterCodeFixesAsync(CodeFixContext)"/> method.
/// </summary>
/// <param name="document">Document to fix.</param>
/// <param name="diagnostic">
/// Diagnostic to fix.
/// The <see cref="Diagnostic.Id"/> of this diagnostic must be in the set of the <see cref="CodeFixProvider.FixableDiagnosticIds"/> of the associated <see cref="CodeFixProvider"/>.
/// </param>
/// <param name="registerCodeFix">Delegate to register a <see cref="CodeAction"/> fixing a subset of diagnostics.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <exception cref="ArgumentNullException">Throws this exception if any of the arguments is null.</exception>
public CodeFixContext(
Document document,
Diagnostic diagnostic,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
CancellationToken cancellationToken)
: this(document, diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), registerCodeFix, verifyArguments: true, cancellationToken: cancellationToken)
{
}
internal CodeFixContext(
Document document,
TextSpan span,
ImmutableArray<Diagnostic> diagnostics,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
bool verifyArguments,
CancellationToken cancellationToken)
: this(document, document.Project, span, diagnostics, registerCodeFix, verifyArguments, isBlocking: false, cancellationToken)
{
}
internal CodeFixContext(
Document document,
TextSpan span,
ImmutableArray<Diagnostic> diagnostics,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
bool verifyArguments,
bool isBlocking,
CancellationToken cancellationToken)
: this(document, document.Project, span, diagnostics, registerCodeFix, verifyArguments, isBlocking, cancellationToken)
{
}
private CodeFixContext(
Document document,
Project project,
TextSpan span,
ImmutableArray<Diagnostic> diagnostics,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
bool verifyArguments,
bool isBlocking,
CancellationToken cancellationToken)
{
if (verifyArguments)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
if (registerCodeFix == null)
{
throw new ArgumentNullException(nameof(registerCodeFix));
}
VerifyDiagnosticsArgument(diagnostics, span);
}
_document = document;
_project = project;
_span = span;
_diagnostics = diagnostics;
_registerCodeFix = registerCodeFix;
_cancellationToken = cancellationToken;
_isBlocking = isBlocking;
}
internal CodeFixContext(
Document document,
Diagnostic diagnostic,
Action<CodeAction, ImmutableArray<Diagnostic>> registerCodeFix,
bool verifyArguments,
CancellationToken cancellationToken)
: this(document, diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), registerCodeFix, verifyArguments, cancellationToken)
{
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of fixes that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the fix.</param>
/// <param name="diagnostic">The subset of <see cref="Diagnostics"/> being addressed / fixed by the <paramref name="action"/>.</param>
public void RegisterCodeFix(CodeAction action, Diagnostic diagnostic)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
if (diagnostic == null)
{
throw new ArgumentNullException(nameof(diagnostic));
}
_registerCodeFix(action, ImmutableArray.Create(diagnostic));
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of fixes that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the fix.</param>
/// <param name="diagnostics">The subset of <see cref="Diagnostics"/> being addressed / fixed by the <paramref name="action"/>.</param>
public void RegisterCodeFix(CodeAction action, IEnumerable<Diagnostic> diagnostics)
{
if (diagnostics == null)
{
throw new ArgumentNullException(nameof(diagnostics));
}
RegisterCodeFix(action, diagnostics.ToImmutableArray());
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of fixes that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the fix.</param>
/// <param name="diagnostics">The subset of <see cref="Diagnostics"/> being addressed / fixed by the <paramref name="action"/>.</param>
public void RegisterCodeFix(CodeAction action, ImmutableArray<Diagnostic> diagnostics)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
VerifyDiagnosticsArgument(diagnostics, _span);
// TODO:
// - Check that all diagnostics are unique (no duplicates).
// - Check that supplied diagnostics form subset of diagnostics originally
// passed to the provider via CodeFixContext.Diagnostics.
_registerCodeFix(action, diagnostics);
}
private static void VerifyDiagnosticsArgument(ImmutableArray<Diagnostic> diagnostics, TextSpan span)
{
if (diagnostics.IsDefault)
{
throw new ArgumentException(nameof(diagnostics));
}
if (diagnostics.Length == 0)
{
throw new ArgumentException(WorkspacesResources.At_least_one_diagnostic_must_be_supplied, nameof(diagnostics));
}
if (diagnostics.Any(d => d == null))
{
throw new ArgumentException(WorkspaceExtensionsResources.Supplied_diagnostic_cannot_be_null, nameof(diagnostics));
}
if (diagnostics.Any(d => d.Location.SourceSpan != span))
{
throw new ArgumentException(string.Format(WorkspacesResources.Diagnostic_must_have_span_0, span.ToString()), nameof(diagnostics));
}
}
}
internal interface ITypeScriptCodeFixContext
{
bool IsBlocking { get; }
}
}