Skip to content

Commit 2aa1c7a

Browse files
authored
Simply the code that generates edits to insert using directives (#11948)
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2493866 I was going to look into why we sometimes get relative Uris from the client or something, and then I looked at the code and thought "we could just not do this".
2 parents f334008 + 5c0cf26 commit 2aa1c7a

File tree

2 files changed

+37
-55
lines changed

2 files changed

+37
-55
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/AddUsingsCodeActionResolver.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Text.Json;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Razor.PooledObjects;
910
using Microsoft.CodeAnalysis.Razor.CodeActions.Models;
1011
using Microsoft.CodeAnalysis.Razor.Formatting;
1112
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
@@ -30,7 +31,25 @@ internal class AddUsingsCodeActionResolver : IRazorCodeActionResolver
3031
var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false);
3132
var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier() { Uri = documentContext.Uri };
3233

33-
return AddUsingsHelper.CreateAddUsingWorkspaceEdit(actionParams.Namespace, actionParams.AdditionalEdit, codeDocument, codeDocumentIdentifier);
34+
using var documentChanges = new PooledArrayBuilder<TextDocumentEdit>();
35+
36+
// Need to add the additional edit first, as the actual usings go at the top of the file, and would
37+
// change the ranges needed in the additional edit if they went in first
38+
if (actionParams.AdditionalEdit is not null)
39+
{
40+
documentChanges.Add(actionParams.AdditionalEdit);
41+
}
42+
43+
documentChanges.Add(new TextDocumentEdit()
44+
{
45+
TextDocument = codeDocumentIdentifier,
46+
Edits = [AddUsingsHelper.CreateAddUsingTextEdit(actionParams.Namespace, codeDocument)]
47+
});
48+
49+
return new WorkspaceEdit()
50+
{
51+
DocumentChanges = documentChanges.ToArray(),
52+
};
3453
}
3554

3655
internal static bool TryCreateAddUsingResolutionParams(string fullyQualifiedName, VSTextDocumentIdentifier textDocument, TextDocumentEdit? additionalEdit, Uri? delegatedDocumentUri, [NotNullWhen(true)] out string? @namespace, [NotNullWhen(true)] out RazorCodeActionResolutionParams? resolutionParams)

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/AddUsingsHelper.cs

Lines changed: 17 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,7 @@ public static async Task<TextEdit[]> GetUsingStatementEditsAsync(RazorCodeDocume
5252
using var edits = new PooledArrayBuilder<TextEdit>();
5353
foreach (var usingStatement in newUsings.Except(oldUsings))
5454
{
55-
// This identifier will be eventually thrown away.
56-
Debug.Assert(codeDocument.Source.FilePath != null);
57-
var identifier = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri(codeDocument.Source.FilePath, UriKind.Relative) };
58-
var workspaceEdit = CreateAddUsingWorkspaceEdit(usingStatement, additionalEdit: null, codeDocument, codeDocumentIdentifier: identifier);
59-
edits.AddRange(workspaceEdit.DocumentChanges!.Value.First.First().Edits.Select(e => (TextEdit)e));
55+
edits.Add(CreateAddUsingTextEdit(usingStatement, codeDocument));
6056
}
6157

6258
return edits.ToArray();
@@ -92,7 +88,7 @@ public static bool TryExtractNamespace(string csharpAddUsing, out string @namesp
9288
return true;
9389
}
9490

95-
public static WorkspaceEdit CreateAddUsingWorkspaceEdit(string @namespace, TextDocumentEdit? additionalEdit, RazorCodeDocument codeDocument, OptionalVersionedTextDocumentIdentifier codeDocumentIdentifier)
91+
public static TextEdit CreateAddUsingTextEdit(string @namespace, RazorCodeDocument codeDocument)
9692
{
9793
/* The heuristic is as follows:
9894
*
@@ -109,34 +105,15 @@ public static WorkspaceEdit CreateAddUsingWorkspaceEdit(string @namespace, TextD
109105
* that now I can come up with a more sophisticated heuristic (something along the lines of checking if
110106
* there's already an ordering, etc.).
111107
*/
112-
using var documentChanges = new PooledArrayBuilder<TextDocumentEdit>();
113-
114-
// Need to add the additional edit first, as the actual usings go at the top of the file, and would
115-
// change the ranges needed in the additional edit if they went in first
116-
if (additionalEdit is not null)
117-
{
118-
documentChanges.Add(additionalEdit);
119-
}
120108

121109
using var usingDirectives = new PooledArrayBuilder<RazorUsingDirective>();
122110
CollectUsingDirectives(codeDocument, ref usingDirectives.AsRef());
123111
if (usingDirectives.Count > 0)
124112
{
125-
// Interpolate based on existing @using statements
126-
var edits = GenerateSingleUsingEditsInterpolated(codeDocument, codeDocumentIdentifier, @namespace, in usingDirectives);
127-
documentChanges.Add(edits);
128-
}
129-
else
130-
{
131-
// Just throw them at the top
132-
var edits = GenerateSingleUsingEditsAtTop(codeDocument, codeDocumentIdentifier, @namespace);
133-
documentChanges.Add(edits);
113+
return GetInsertUsingTextEdit(codeDocument, @namespace, in usingDirectives);
134114
}
135115

136-
return new WorkspaceEdit()
137-
{
138-
DocumentChanges = documentChanges.ToArray(),
139-
};
116+
return GetInsertUsingTextEdit(codeDocument, @namespace);
140117
}
141118

142119
public static async Task<ImmutableArray<string>> FindUsingDirectiveStringsAsync(SyntaxTree syntaxTree, CancellationToken cancellationToken)
@@ -165,15 +142,16 @@ static string GetNamespaceFromDirective(UsingDirectiveSyntax usingDirectiveSynta
165142
}
166143
}
167144

168-
private static TextDocumentEdit GenerateSingleUsingEditsInterpolated(
145+
/// <summary>
146+
/// Generates a <see cref="TextEdit"/> to insert a new using directive into the Razor code document, at the right spot among existing using directives.
147+
/// </summary>
148+
private static TextEdit GetInsertUsingTextEdit(
169149
RazorCodeDocument codeDocument,
170-
OptionalVersionedTextDocumentIdentifier codeDocumentIdentifier,
171150
string newUsingNamespace,
172151
ref readonly PooledArrayBuilder<RazorUsingDirective> existingUsingDirectives)
173152
{
174153
Debug.Assert(existingUsingDirectives.Count > 0);
175154

176-
using var edits = new PooledArrayBuilder<SumType<TextEdit, AnnotatedTextEdit>>();
177155
var newText = $"@using {newUsingNamespace}{Environment.NewLine}";
178156

179157
foreach (var usingDirective in existingUsingDirectives)
@@ -188,31 +166,21 @@ private static TextDocumentEdit GenerateSingleUsingEditsInterpolated(
188166
if (string.CompareOrdinal(newUsingNamespace, usingDirectiveNamespace) < 0)
189167
{
190168
var usingDirectiveLineIndex = codeDocument.Source.Text.GetLinePosition(usingDirective.Node.Span.Start).Line;
191-
var edit = LspFactory.CreateTextEdit(line: usingDirectiveLineIndex, character: 0, newText);
192-
edits.Add(edit);
193-
break;
169+
return LspFactory.CreateTextEdit(line: usingDirectiveLineIndex, character: 0, newText);
194170
}
195171
}
196172

197173
// If we haven't actually found a place to insert the using directive, do so at the end
198-
if (edits.Count == 0)
199-
{
200-
var endIndex = existingUsingDirectives[^1].Node.Span.End;
201-
var lineIndex = GetLineIndexOrEnd(codeDocument, endIndex - 1) + 1;
202-
var edit = LspFactory.CreateTextEdit(line: lineIndex, character: 0, newText);
203-
edits.Add(edit);
204-
}
205-
206-
return new TextDocumentEdit()
207-
{
208-
TextDocument = codeDocumentIdentifier,
209-
Edits = edits.ToArray()
210-
};
174+
var endIndex = existingUsingDirectives[^1].Node.Span.End;
175+
var lineIndex = GetLineIndexOrEnd(codeDocument, endIndex - 1) + 1;
176+
return LspFactory.CreateTextEdit(line: lineIndex, character: 0, newText);
211177
}
212178

213-
private static TextDocumentEdit GenerateSingleUsingEditsAtTop(
179+
/// <summary>
180+
/// Generates a <see cref="TextEdit"/> to insert a new using directive into the Razor code document, at the top of the file.
181+
/// </summary>
182+
private static TextEdit GetInsertUsingTextEdit(
214183
RazorCodeDocument codeDocument,
215-
OptionalVersionedTextDocumentIdentifier codeDocumentIdentifier,
216184
string newUsingNamespace)
217185
{
218186
var insertPosition = (0, 0);
@@ -229,12 +197,7 @@ private static TextDocumentEdit GenerateSingleUsingEditsAtTop(
229197
insertPosition = (lineIndex, 0);
230198
}
231199

232-
// Insert all usings at the given point
233-
return new TextDocumentEdit
234-
{
235-
TextDocument = codeDocumentIdentifier,
236-
Edits = [LspFactory.CreateTextEdit(insertPosition, newText: $"@using {newUsingNamespace}{Environment.NewLine}")]
237-
};
200+
return LspFactory.CreateTextEdit(insertPosition, newText: $"@using {newUsingNamespace}{Environment.NewLine}");
238201
}
239202

240203
private static int GetLineIndexOrEnd(RazorCodeDocument codeDocument, int endIndex)

0 commit comments

Comments
 (0)