Skip to content

Conversation

@davidwengier
Copy link
Member

Fixes #12608

Previous code was making bad assumptions about everything being in one project, and just using hint name to identify a generated document. New code uses SourceGeneratedDocumentIdentity, which can reason about projects, and hides direct hint name use as much as possible.

@davidwengier davidwengier requested a review from a team as a code owner December 18, 2025 00:42
""";

var solution = LocalWorkspace.CurrentSolution;
var project1 = AddProjectAndRazorDocument(solution, TestProjectData.SomeProject.FilePath, someProjectId, surveyPromptId, TestProjectData.SomeProjectComponentFile1.FilePath, surveyPrompt.Text).Project;
Copy link
Contributor

Choose a reason for hiding this comment

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

AddProjectAndRazorDocument

aside: seems odd this method would need to take in a projectid and documentid and not just generate them itself. Or is this method potentially called on existing projectid/documentids?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, to simulate OOP syncing in tests we create two solutions with identical projects and documents, but different MEF compositions, so the IDs have to match.

?? ThrowHelper.ThrowInvalidOperationException<Project>($"The project {projectKey} did not exist in {solution}.");
}

public static bool TryGetSourceGeneratedDocumentIdentity(this Solution solution, Uri generatedDocumentUri, out RazorGeneratedDocumentIdentity identity)
Copy link
Contributor

Choose a reason for hiding this comment

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

TryGetSourceGeneratedDocument

Dumb question:

Could this just return the SourceGeneratedDocument directly, instead of having the callers understand the identity stuff?

Copy link
Member Author

@davidwengier davidwengier Jan 5, 2026

Choose a reason for hiding this comment

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

AFAIK getting the source generated document would mean running the source generators, this can get the identity without doing that. Also, getting the source generated document is only useful if that's what you need to work with. To get the originating Razor document for a source generated document, you'd need to go back to the identity anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just to clarify, I was thinking along something like:

public static async Task<SourceGeneratedDocument?> TryGetSourceGeneratedDocumentAsync(this Solution solution, Uri generatedDocumentUri, CancellationToken cancellationToken)
{
    if (!RazorUri.IsGeneratedDocumentUri(generatedDocumentUri) ||
        !solution.TryGetSourceGeneratedDocumentIdentity(generatedDocumentUri, out var identity) ||
        !solution.TryGetProject(identity.DocumentId.ProjectId, out var project))
    {
        return null;
    }

    return await project.TryGetCSharpDocumentForGeneratedDocumentAsync(identity, cancellationToken).ConfigureAwait(false);
}

in SolutionExtensions.cs and something like:

public async Task<RazorCodeDocument?> TryGetSourceGeneratedDocumentAsync(Solution solution, Uri generatedDocumentUri, CancellationToken cancellationToken)
{
    if (!RazorUri.IsGeneratedDocumentUri(generatedDocumentUri) ||
        !solution.TryGetSourceGeneratedDocumentIdentity(generatedDocumentUri, out var identity) ||
        !identity.IsRazorSourceGeneratedDocument() ||
        !solution.TryGetProject(identity.DocumentId.ProjectId, out var project))
    {
        return null;
    }

    return await GetSnapshot(project).TryGetCodeDocumentForGeneratedDocumentAsync(identity, cancellationToken).ConfigureAwait(false);
}

in RemoteSnapshotManager.cs. But maybe that still has the issues that you called out?

Copy link
Member Author

Choose a reason for hiding this comment

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

ohhh, I see what you're saying, helper methods for the common scenarios. Yes, that would work. This method might still need to stay too, but I should be able to simplify some of the calling code. Will take a look

Copy link
Member Author

Choose a reason for hiding this comment

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

Logged #12637 to follow up, probably post-snap

Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

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

:shipit:

@davidwengier davidwengier merged commit f7ff382 into dotnet:main Jan 5, 2026
10 checks passed
@davidwengier davidwengier deleted the FixCrossProjectMapping branch January 5, 2026 22:26
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 5, 2026
@davidwengier davidwengier modified the milestones: Next, 18.3 Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RemoteDocumentMappingService.MapToHostDocumentUriAndRangeAsync doesn't work across projects

2 participants