diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs
index 67b0359dadf..1615b839e7c 100644
--- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs
+++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs
@@ -1,12 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.AspNetCore.Razor.Language;
using System;
-using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.Threading;
-using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.NET.Sdk.Razor.SourceGenerators;
@@ -65,7 +63,11 @@ public SourceGeneratorRazorCodeDocument ProcessInitialParse(RazorProjectItem pro
return new SourceGeneratorRazorCodeDocument(codeDocument);
}
- public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCodeDocument sgDocument, TagHelperCollection tagHelpers, bool checkForIdempotency, CancellationToken cancellationToken)
+ public SourceGeneratorRazorCodeDocument ProcessTagHelpers(
+ SourceGeneratorRazorCodeDocument sgDocument,
+ TagHelperCollection tagHelpers,
+ bool checkForIdempotency,
+ CancellationToken cancellationToken)
{
Debug.Assert(sgDocument.CodeDocument.GetPreTagHelperSyntaxTree() is not null);
@@ -88,12 +90,11 @@ public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCo
// re-run discovery to figure out which tag helpers are now in scope for this document
codeDocument.SetTagHelpers(tagHelpers);
_discoveryPhase.Execute(codeDocument, cancellationToken);
- var tagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers;
+
+ var newTagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers;
// Check if any new tag helpers were added or ones we previously used were removed
- var newVisibleTagHelpers = tagHelpersInScope.Except(previousTagHelpersInScope);
- var newUnusedTagHelpers = previousUsedTagHelpers.Except(tagHelpersInScope);
- if (!newVisibleTagHelpers.Any() && !newUnusedTagHelpers.Any())
+ if (!RequiresRewrite(newTagHelpersInScope, previousTagHelpersInScope, previousUsedTagHelpers))
{
// No newly visible tag helpers, and any that got removed weren't used by this document anyway
return sgDocument;
@@ -112,6 +113,56 @@ public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCo
return new SourceGeneratorRazorCodeDocument(codeDocument);
}
+ private static bool RequiresRewrite(
+ TagHelperCollection newTagHelpers,
+ TagHelperCollection previousTagHelpers,
+ TagHelperCollection previousUsedTagHelpers)
+ {
+ // Check if any new tag helpers were added (that weren't in scope before)
+ // Check if any previously used tag helpers were removed (no longer in scope)
+ return HasAnyNotIn(newTagHelpers, previousTagHelpers) ||
+ HasAnyNotIn(previousUsedTagHelpers, newTagHelpers);
+ }
+
+ ///
+ /// Determines whether the first collection contains any tag helper descriptors that are not present
+ /// in the second collection.
+ ///
+ /// The collection to check for unique items.
+ /// The collection to compare against.
+ ///
+ /// if contains any descriptors not present in
+ /// ; otherwise, .
+ ///
+ private static bool HasAnyNotIn(TagHelperCollection first, TagHelperCollection second)
+ {
+ if (first.IsEmpty)
+ {
+ return false;
+ }
+
+ if (second.IsEmpty)
+ {
+ return true;
+ }
+
+ if (first.Equals(second))
+ {
+ return false;
+ }
+
+ // For each item in the first collection, check if it exists in the second collection
+ foreach (var item in first)
+ {
+ if (!second.Contains(item))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public SourceGeneratorRazorCodeDocument ProcessRemaining(SourceGeneratorRazorCodeDocument sgDocument, CancellationToken cancellationToken)
{
var codeDocument = sgDocument.CodeDocument;