-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Allow rename to (optionally) process source generated documents #78984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6c55132
8a77f68
8f06ff5
58ca7fd
d4aa226
5a684cf
0623c61
3721ae9
4d56fb6
c7ef883
0a3e34b
e9b4dd1
b12b57e
2c4818b
0e534c0
3114486
a0ae77e
8ef6ace
ea30bb5
4868f75
26b72b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| using Microsoft.CodeAnalysis.LanguageServer.Handler; | ||
| using Microsoft.CodeAnalysis.NavigateTo; | ||
| using Microsoft.CodeAnalysis.PooledObjects; | ||
| using Microsoft.CodeAnalysis.Shared.Extensions; | ||
| using Microsoft.CodeAnalysis.SpellCheck; | ||
| using Microsoft.CodeAnalysis.Tags; | ||
| using Microsoft.CodeAnalysis.Text; | ||
|
|
@@ -388,15 +389,15 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) | |
| /// Compute all the <see cref="LSP.TextDocumentEdit"/> for the input list of changed documents. | ||
| /// Additionally maps the locations of the changed documents if necessary. | ||
| /// </summary> | ||
| public static async Task<LSP.TextDocumentEdit[]> ChangedDocumentsToTextDocumentEditsAsync<T>(IEnumerable<DocumentId> changedDocuments, Func<DocumentId, T> getNewDocumentFunc, | ||
| Func<DocumentId, T> getOldDocumentFunc, IDocumentTextDifferencingService? textDiffService, CancellationToken cancellationToken) where T : TextDocument | ||
| public static async Task<LSP.TextDocumentEdit[]> ChangedDocumentsToTextDocumentEditsAsync(IEnumerable<DocumentId> changedDocuments, Solution newSolution, | ||
| Solution oldSolution, IDocumentTextDifferencingService? textDiffService, CancellationToken cancellationToken) | ||
| { | ||
| using var _ = ArrayBuilder<(DocumentUri Uri, LSP.TextEdit TextEdit)>.GetInstance(out var uriToTextEdits); | ||
|
|
||
| foreach (var docId in changedDocuments) | ||
| { | ||
| var newDocument = getNewDocumentFunc(docId); | ||
| var oldDocument = getOldDocumentFunc(docId); | ||
| var newDocument = await newSolution.GetRequiredDocumentAsync(docId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); | ||
| var oldDocument = await oldSolution.GetRequiredDocumentAsync(docId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); | ||
|
Comment on lines
+399
to
+400
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is only one caller of this method (now?) so the abstraction of using delegates seemed unnecessary. |
||
|
|
||
| var oldText = await oldDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(false); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,7 +33,7 @@ public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.PrepareRenamePar | |
| var position = await document.GetPositionFromLinePositionAsync(linePosition, cancellationToken).ConfigureAwait(false); | ||
|
|
||
| var symbolicRenameInfo = await SymbolicRenameInfo.GetRenameInfoAsync( | ||
| document, position, cancellationToken).ConfigureAwait(false); | ||
| document, position, includeSourceGenerated: false, cancellationToken).ConfigureAwait(false); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question. basically, it's not apparent to me at callsites what teh right value is here. |
||
| if (symbolicRenameInfo.IsError) | ||
| return null; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,23 +28,24 @@ internal sealed class RenameHandler() : ILspServiceDocumentRequestHandler<LSP.Re | |
| public TextDocumentIdentifier GetTextDocumentIdentifier(RenameParams request) => request.TextDocument; | ||
|
|
||
| public Task<WorkspaceEdit?> HandleRequestAsync(RenameParams request, RequestContext context, CancellationToken cancellationToken) | ||
| => GetRenameEditAsync(context.GetRequiredDocument(), ProtocolConversions.PositionToLinePosition(request.Position), request.NewName, cancellationToken); | ||
| => GetRenameEditAsync(context.GetRequiredDocument(), ProtocolConversions.PositionToLinePosition(request.Position), request.NewName, includeSourceGenerated: false, cancellationToken); | ||
|
|
||
| internal static async Task<WorkspaceEdit?> GetRenameEditAsync(Document document, LinePosition linePosition, string newName, CancellationToken cancellationToken) | ||
| internal static async Task<WorkspaceEdit?> GetRenameEditAsync(Document document, LinePosition linePosition, string newName, bool includeSourceGenerated, CancellationToken cancellationToken) | ||
| { | ||
| var oldSolution = document.Project.Solution; | ||
| var position = await document.GetPositionFromLinePositionAsync(linePosition, cancellationToken).ConfigureAwait(false); | ||
|
|
||
| var symbolicRenameInfo = await SymbolicRenameInfo.GetRenameInfoAsync( | ||
| document, position, cancellationToken).ConfigureAwait(false); | ||
| document, position, includeSourceGenerated, cancellationToken).ConfigureAwait(false); | ||
| if (symbolicRenameInfo.IsError) | ||
| return null; | ||
|
|
||
| var options = new SymbolRenameOptions( | ||
| RenameOverloads: false, | ||
| RenameInStrings: false, | ||
| RenameInComments: false, | ||
| RenameFile: false); | ||
| renameOverloads: false, | ||
| renameInStrings: false, | ||
| renameInComments: false, | ||
| renameFile: false, | ||
| renameInSourceGeneratedDocuments: includeSourceGenerated); | ||
|
|
||
| var renameLocationSet = await Renamer.FindRenameLocationsAsync( | ||
| oldSolution, | ||
|
|
@@ -70,14 +71,18 @@ internal sealed class RenameHandler() : ILspServiceDocumentRequestHandler<LSP.Re | |
| // Then we can just take the text changes from the first document to avoid returning duplicate edits. | ||
| renamedSolution = await renamedSolution.WithMergedLinkedFileChangesAsync(oldSolution, solutionChanges, cancellationToken: cancellationToken).ConfigureAwait(false); | ||
| solutionChanges = renamedSolution.GetChanges(oldSolution); | ||
|
|
||
| Contract.ThrowIfTrue(!includeSourceGenerated && !renamedSolution.CompilationState.FrozenSourceGeneratedDocumentStates.IsEmpty, "Renaming in generated documents is not allowed, but there are changes in source generated documents."); | ||
|
|
||
| var changedDocuments = solutionChanges | ||
| .GetProjectChanges() | ||
| .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true)) | ||
| .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First()); | ||
| .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First()) | ||
| .Concat(solutionChanges.GetExplicitlyChangedSourceGeneratedDocuments()); | ||
davidwengier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| var textDiffService = renamedSolution.Services.GetRequiredService<IDocumentTextDifferencingService>(); | ||
|
|
||
| var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution.GetRequiredDocument, oldSolution.GetRequiredDocument, | ||
| var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution, oldSolution, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A couple of questions here
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very good questions! I'll try to be brief in my answers, but things get complicated quick :)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update to answer 2: Razor filters out any edits to source generated documents that aren't Razor documents by virtue of not being able to answer the question "Which Razor file is this generated document for?", so edits for other source generators will never escape into the real world. Going to push a commit to this PR to allow us to make this check more robust in future. |
||
| textDiffService, cancellationToken).ConfigureAwait(false); | ||
|
|
||
| return new WorkspaceEdit { DocumentChanges = documentEdits }; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why 'false' here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only place that opts in to renames in generated files is the one entry point Razor uses. For now anyway.