diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs index 55687253d01..faf72056bfb 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs @@ -173,16 +173,37 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return true; } - if (oldSymbol is IAssemblySymbol oldAssembly && newSymbol is IAssemblySymbol newAssembly) + if (oldSymbol is not IAssemblySymbol oldAssembly || newSymbol is not IAssemblySymbol newAssembly) { - var oldModuleMVIDs = oldAssembly.Modules.Select(GetMVID); - var newModuleMVIDs = newAssembly.Modules.Select(GetMVID); - return oldModuleMVIDs.SequenceEqual(newModuleMVIDs); + return false; + } + + // Compare the MVIDs of the modules in each assembly. If they aren't present or don't match we don't consider them equal + var oldModules = oldAssembly.Modules.ToArray(); + var newModules = newAssembly.Modules.ToArray(); + if (oldModules.Length != newModules.Length) + { + return false; + } - static Guid GetMVID(IModuleSymbol m) => m.GetMetadata()?.GetModuleVersionId() ?? Guid.Empty; + for (int i = 0; i < oldModules.Length; i++) + { + var oldMetadata = oldModules[i].GetMetadata(); + var newMetadata = newModules[i].GetMetadata(); + + if (oldMetadata is null || newMetadata is null) + { + return false; + } + + if (oldMetadata.GetModuleVersionId() != newMetadata.GetModuleVersionId()) + { + return false; + } } - return false; + // All module MVIDs matched. + return true; }))) { return false; diff --git a/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/RazorSourceGeneratorTests.cs b/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/RazorSourceGeneratorTests.cs index ac91bdf7606..e597fabd87d 100644 --- a/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/RazorSourceGeneratorTests.cs +++ b/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/RazorSourceGeneratorTests.cs @@ -3605,5 +3605,85 @@ public async Task IncrementalCompilation_RerunsGenerator_When_AdditionalFileRena var newCouNterSource = result.GeneratedSources.FirstOrDefault(s => s.HintName.Contains("NewCouNter")); Assert.Contains("public partial class NewCouNter", newCouNterSource.SourceText.ToString()); } + + [Fact, WorkItem("https://github.com/dotnet/razor/issues/12316")] + public async Task RazorClassLibrary_Change_Updates_DependentProject_WhenReferencedAsCompilation() + { + var rclProject = CreateTestProject(new() + { + ["LibComponent.razor"] = "
Library component
", + }); + rclProject = rclProject.WithAssemblyName("RazorClassLibrary"); + + var rclCompilation = await rclProject.GetCompilationAsync(); + var rclDriver = await GetDriverAsync(rclProject); + var rclRun = RunGenerator(rclCompilation!, ref rclDriver, out var rclOutputCompilation); + Assert.Empty(rclRun.Diagnostics); + Assert.Single(rclRun.GeneratedSources); // LibComponent + + // Explicitly use a CompilationReference + var rclReference = rclOutputCompilation.ToMetadataReference(); + + // Create the main project that references the RCL and uses its component. + var mainProject = CreateTestProject(new() + { + ["Pages/Index.razor"] = "Library component
", + }).WithAssemblyName("RazorClassLibrary"); + + rclCompilation = await rclProject.GetCompilationAsync()!; + rclDriver = await GetDriverAsync(rclProject); + rclRun = RunGenerator(rclCompilation!, ref rclDriver, out rclOutputCompilation); + Assert.Empty(rclRun.Diagnostics); + Assert.Single(rclRun.GeneratedSources); // RenamedComponent + + var rclReference2 = rclOutputCompilation.ToMetadataReference(); + + // Update main project to point to the new reference (with renamed component). + mainProject = mainProject.RemoveMetadataReference(rclReference) + .AddMetadataReference(rclReference2); + mainCompilation = await mainProject.GetCompilationAsync(); + + // Re-run generator: expect missing component diagnostic (RZ10012). + mainRun = RunGenerator(mainCompilation!, ref mainDriver); + var missing = Assert.Single(mainRun.Diagnostics); + Assert.Equal("RZ10012", missing.Id); + + // Update main project's Index.razor to use the renamed component. + var updatedIndex = new TestAdditionalText("Pages/Index.razor", SourceText.From("