Skip to content

Conversation

@davidwengier
Copy link
Member

@davidwengier davidwengier commented Jun 16, 2025

Part of dotnet/razor#11831

Razor side that completes the fix is dotnet/razor#11952

I am well out of my depth with rename, and have commented on a couple of spots that might be contentious, or are otherwise worth noting.

Comment on lines +400 to +401
var newDocument = await newSolution.GetRequiredDocumentAsync(docId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
var oldDocument = await oldSolution.GetRequiredDocumentAsync(docId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View with whitespace off, most of the changes were just modernizing the file to raw string literals

// scenarios that wanted it.
if (documentId.IsSourceGenerated)
{
_ = await partiallyRenamedSolution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, _cancellationToken).ConfigureAwait(false);
Copy link
Member Author

@davidwengier davidwengier Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I did the changes to allow WithDocumentXXX to work on source generated documents, I made it only work for already generated documents because Razor could guarantee that, and it seemed less risky for any other scenario. I didn't appreciate, however, how rename works and how much it likes to fork solutions.

This line of code is the downside of that decision, where this (and the other spot it appears) unfortunately has to force the generated document to be created, just to change it again. For now at least I think it's better to do this, than to allow the WithDocumentXXX methods to work on unrealised source generated documents. As per the comment in the file, this should only happen when Razor explicitly opts in to rename in source generated documents.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't love this. but i don't mind it either, and i have no better solution. nad the fallout is contained and the comment is clear enough.

Comment on lines -237 to +238
var projectOpt = conflictResolution.CurrentSolution.GetProject(renamedSymbol.ContainingAssembly, cancellationToken);
var projectOpt = conflictResolution.CurrentSolution.GetProject(projectId);
Copy link
Member Author

@davidwengier davidwengier Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetProject method that takes an assembly symbol uses the compilation tracker to work, and with source generators the compilation tracker stuff gets odd. Fortunately, the one caller of this method already has the project Id to hand, so it was easiest to just pass it in.

It's possible my understanding of the code is incorrect though, so maybe this is a bad change, that just happens to not be covered by any existing tests?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking up project by assembly always makes me nervous. are you sure those that ProjectId refers to the project the current symbol is in, not hte original symbol being renamed? this matters for things likes cascades across projects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically, i love this. but needs a bit of an audit just to make firmly sure this project id is what we expect.

@davidwengier davidwengier marked this pull request as ready for review June 16, 2025 06:34
@davidwengier davidwengier requested a review from a team as a code owner June 16, 2025 06:34
Copy link
Member

@dibarbet dibarbet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

someone more familiar with the rename internals should look at that part

var textDiffService = renamedSolution.Services.GetRequiredService<IDocumentTextDifferencingService>();

var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution.GetRequiredDocument, oldSolution.GetRequiredDocument,
var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution, oldSolution,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of questions here

  1. Are you expecting the renamed locations in the generated files to be mapped here via the span mapping service? IIRC we do that.
  2. How do you know if the rename is touching razor generated files, vs other generated files? Do you exclude files you don't know about?

Copy link
Member Author

Choose a reason for hiding this comment

The 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 :)

  1. In the context of this PR, no I'm not expecting that. Razor will remap the results when they come through. Additionally in cohosting there is no span mapping service at all (yet?). Additionally additionally, the span mapping that this method does is only helping in IDE scenarios where Roslyn is using LSP for rename. Those will regress in cohosting for now, and I'm leaving that as a separate fix.
  2. At the moment no effort is made to constrain the documents, though that might have to come later for other reasons. I should check that the editor doesn't crash or do something horrible, but in general I don't think creating an edit for a source generated document is a terrible thing, because it will just be thrown away at some point, and the file will be regenerated. That's essentially what happens with the Razor source generated documents too, we don't ever expect to apply the edits, we just need Roslyn to tell us what they would be.

Copy link
Member Author

@davidwengier davidwengier Jun 18, 2025

Choose a reason for hiding this comment

The 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.

Copy link
Member

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tentatively approving. morally i'm ok with this. and this really is mostly just an option flowing through.

A couple of things i would like to see:

  1. naming. I prefer includeSourceGenerated
  2. options. we have an options type... it feels like thsi sould be part of it.
  3. minor cleanup suggestions.
  4. get sign off from davidb on the LSP side. i don't know that stuff well and i want him ok with it. the rest of hte workspace/rename side seems fine.

public async Task<IInlineRenameInfo> GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken)
{
var symbolicInfo = await SymbolicRenameInfo.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);
var symbolicInfo = await SymbolicRenameInfo.GetRenameInfoAsync(document, position, includeSourceGenerated: false, cancellationToken).ConfigureAwait(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why 'false' here?

Copy link
Member Author

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.


var symbolicRenameInfo = await SymbolicRenameInfo.GetRenameInfoAsync(
document, position, cancellationToken).ConfigureAwait(false);
document, position, includeSourceGenerated: false, cancellationToken).ConfigureAwait(false);
Copy link
Member

Choose a reason for hiding this comment

The 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.

@CyrusNajmabadi CyrusNajmabadi self-requested a review June 27, 2025 16:25
Copy link
Member

@dibarbet dibarbet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lps side seems fine

@davidwengier
Copy link
Member Author

Thanks all!

@davidwengier davidwengier merged commit f2649bb into dotnet:main Jul 8, 2025
25 checks passed
@davidwengier davidwengier deleted the RazorCohostRename branch July 8, 2025 21:43
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jul 8, 2025
davidwengier added a commit to dotnet/razor that referenced this pull request Jul 17, 2025
Fixes #11831

This needs dotnet/roslyn#78984 to go in first,
or the test will fail. Which you should see in this PR!
@RikkiGibson RikkiGibson modified the milestones: Next, 18.0 P1 Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants