diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/CreateNewOnMetadataUpdateAttributePass.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/CreateNewOnMetadataUpdateAttributePass.cs
index cfac39e1429322c231b883ede0304eafd2bd92ff..9c81968d164b57e290c5a4902684cace1b523308 100644
--- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/CreateNewOnMetadataUpdateAttributePass.cs
+++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/CreateNewOnMetadataUpdateAttributePass.cs
@@ -16,9 +16,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
     {
         protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
         {
-            if (FileKinds.IsComponent(codeDocument.GetFileKind()))
+            if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind &&
+                documentNode.DocumentKind != MvcViewDocumentClassifierPass.MvcViewDocumentKind)
             {
-                // Hot reload does not apply to components.
+                // Not a MVC file. Skip.
                 return;
             }
 
diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ModelExpressionPass.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ModelExpressionPass.cs
index ff4490563a0e105deaca6c271bf35eb20daa8ba1..6bbceb73f878223cebb67ef9ef43caa12aee6e85 100644
--- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ModelExpressionPass.cs
+++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ModelExpressionPass.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
@@ -15,6 +15,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
 
         protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
         {
+            if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind &&
+                documentNode.DocumentKind != MvcViewDocumentClassifierPass.MvcViewDocumentKind)
+            {
+                // Not a MVC file. Skip.
+                return;
+            }
+
             var visitor = new Visitor();
             visitor.Visit(documentNode);
         }
diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ViewComponentTagHelperPass.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ViewComponentTagHelperPass.cs
index cc0b873e060a0b3cb2478b840144f95b43f6b5c6..e9b2191d44fef2952f67058383ae46d98a4a4b0c 100644
--- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ViewComponentTagHelperPass.cs
+++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/ViewComponentTagHelperPass.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
@@ -15,6 +15,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
 
         protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
         {
+            if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind &&
+                documentNode.DocumentKind != MvcViewDocumentClassifierPass.MvcViewDocumentKind)
+            {
+                // Not a MVC file. Skip.
+                return;
+            }
+
             var @namespace = documentNode.FindPrimaryNamespace();
             var @class = documentNode.FindPrimaryClass();
             if (@namespace == null || @class == null)
diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelExpressionPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelExpressionPassTest.cs
index 3465e29ef5916395ca271dc17714558b3b6f3458..9f79d631a57353d21dc1ec3a7c4d813570bb291c 100644
--- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelExpressionPassTest.cs
+++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelExpressionPassTest.cs
@@ -170,7 +170,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
                 }
             }
 
-            return codeDocument.GetDocumentIntermediateNode();
+            var irNode = codeDocument.GetDocumentIntermediateNode();
+            irNode.DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind;
+
+            return irNode;
         }
 
         private TagHelperIntermediateNode FindTagHelperNode(IntermediateNode node)
@@ -205,4 +208,4 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultAllowedChildTagDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultAllowedChildTagDescriptorBuilder.cs
index eeb5de2442182644e93a404fc3fa56e285f54c59..595f782e52064f538ad6d36828332f689f36ab1a 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultAllowedChildTagDescriptorBuilder.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultAllowedChildTagDescriptorBuilder.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
@@ -36,10 +36,10 @@ namespace Microsoft.AspNetCore.Razor.Language
 
         public AllowedChildTagDescriptor Build()
         {
-            var validationDiagnostics = Validate();
-            var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
+            var diagnostics = Validate();
             if (_diagnostics != null)
             {
+                diagnostics ??= new();
                 diagnostics.UnionWith(_diagnostics);
             }
 
@@ -47,31 +47,35 @@ namespace Microsoft.AspNetCore.Razor.Language
             var descriptor = new DefaultAllowedChildTagDescriptor(
                 Name,
                 displayName,
-                diagnostics.ToArray());
+                diagnostics?.ToArray() ?? Array.Empty<RazorDiagnostic>());
 
             return descriptor;
         }
 
-        private IEnumerable<RazorDiagnostic> Validate()
+        private HashSet<RazorDiagnostic> Validate()
         {
+            HashSet<RazorDiagnostic> diagnostics = null;
             if (string.IsNullOrWhiteSpace(Name))
             {
                 var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChildNullOrWhitespace(_parent.GetDisplayName());
 
-                yield return diagnostic;
+                diagnostics ??= new();
+                diagnostics.Add(diagnostic);
             }
             else if (Name != TagHelperMatchingConventions.ElementCatchAllName)
             {
                 foreach (var character in Name)
                 {
-                    if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                    if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                     {
                         var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChild(_parent.GetDisplayName(), Name, character);
-
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
                 }
             }
+
+            return diagnostics;
         }
     }
 }
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs
index 8bae2309d7a3328c8bfd8251d508e51698ce0b13..a9b9eb456e22baa56636b6dd3e7ef4d10767569b 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs
@@ -92,10 +92,10 @@ namespace Microsoft.AspNetCore.Razor.Language
 
         public BoundAttributeDescriptor Build()
         {
-            var validationDiagnostics = Validate();
-            var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
+            var diagnostics = Validate();
             if (_diagnostics != null)
             {
+                diagnostics ??= new();
                 diagnostics.UnionWith(_diagnostics);
             }
 
@@ -125,7 +125,7 @@ namespace Microsoft.AspNetCore.Razor.Language
                 CaseSensitive,
                 parameters,
                 new Dictionary<string, string>(Metadata),
-                diagnostics.ToArray())
+                diagnostics?.ToArray() ?? Array.Empty<RazorDiagnostic>())
             {
                 IsEditorRequired = IsEditorRequired,
             };
@@ -159,13 +159,15 @@ namespace Microsoft.AspNetCore.Razor.Language
             return Name;
         }
 
-        private IEnumerable<RazorDiagnostic> Validate()
+        private HashSet<RazorDiagnostic> Validate()
         {
             // data-* attributes are explicitly not implemented by user agents and are not intended for use on
             // the server; therefore it's invalid for TagHelpers to bind to them.
             const string DataDashPrefix = "data-";
             var isDirectiveAttribute = this.IsDirectiveAttribute();
 
+            HashSet<RazorDiagnostic> diagnostics = null;
+
             if (string.IsNullOrWhiteSpace(Name))
             {
                 if (IndexerAttributeNamePrefix == null)
@@ -174,7 +176,8 @@ namespace Microsoft.AspNetCore.Razor.Language
                         _parent.GetDisplayName(),
                         GetDisplayName());
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
             }
             else
@@ -186,7 +189,8 @@ namespace Microsoft.AspNetCore.Razor.Language
                         GetDisplayName(),
                         Name);
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
 
                 StringSegment name = Name;
@@ -201,13 +205,14 @@ namespace Microsoft.AspNetCore.Razor.Language
                             GetDisplayName(),
                             Name);
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
 
                 for (var i = 0; i < name.Length; i++)
                 {
                     var character = name[i];
-                    if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                    if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                     {
                         var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeName(
                             _parent.GetDisplayName(),
@@ -215,7 +220,8 @@ namespace Microsoft.AspNetCore.Razor.Language
                             name.Value,
                             character);
 
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
                 }
             }
@@ -229,7 +235,8 @@ namespace Microsoft.AspNetCore.Razor.Language
                         GetDisplayName(),
                         IndexerAttributeNamePrefix);
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
                 else if (IndexerAttributeNamePrefix.Length > 0 && string.IsNullOrWhiteSpace(IndexerAttributeNamePrefix))
                 {
@@ -237,7 +244,8 @@ namespace Microsoft.AspNetCore.Razor.Language
                         _parent.GetDisplayName(),
                         GetDisplayName());
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
                 else
                 {
@@ -253,13 +261,14 @@ namespace Microsoft.AspNetCore.Razor.Language
                             GetDisplayName(),
                             indexerPrefix.Value);
 
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
 
                     for (var i = 0; i < indexerPrefix.Length; i++)
                     {
                         var character = indexerPrefix[i];
-                        if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                        if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                         {
                             var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributePrefix(
                                 _parent.GetDisplayName(),
@@ -267,11 +276,14 @@ namespace Microsoft.AspNetCore.Razor.Language
                                 indexerPrefix.Value,
                                 character);
 
-                            yield return diagnostic;
+                            diagnostics ??= new();
+                            diagnostics.Add(diagnostic);
                         }
                     }
                 }
             }
+
+            return diagnostics;
         }
 
         private void EnsureAttributeParameterBuilders()
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs
index c93115fe45364d67448af831034cf09c5e21337b..82670124298bb785627e09f8bf2a936a1c6be16f 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs
@@ -1,6 +1,7 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 
@@ -51,10 +52,10 @@ namespace Microsoft.AspNetCore.Razor.Language
 
         public BoundAttributeParameterDescriptor Build()
         {
-            var validationDiagnostics = Validate();
-            var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
+            var diagnostics = Validate();
             if (_diagnostics != null)
             {
+                diagnostics ??= new();
                 diagnostics.UnionWith(_diagnostics);
             }
             var descriptor = new DefaultBoundAttributeParameterDescriptor(
@@ -66,7 +67,7 @@ namespace Microsoft.AspNetCore.Razor.Language
                 GetDisplayName(),
                 CaseSensitive,
                 new Dictionary<string, string>(Metadata),
-                diagnostics.ToArray());
+                diagnostics?.ToArray() ?? Array.Empty<RazorDiagnostic>());
 
             return descriptor;
         }
@@ -81,28 +82,34 @@ namespace Microsoft.AspNetCore.Razor.Language
             return $":{Name}";
         }
 
-        private IEnumerable<RazorDiagnostic> Validate()
+        private HashSet<RazorDiagnostic> Validate()
         {
+            HashSet<RazorDiagnostic> diagnostics = null;
             if (string.IsNullOrWhiteSpace(Name))
             {
+
                 var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeParameterNullOrWhitespace(_parent.Name);
-                yield return diagnostic;
+                diagnostics ??= new();
+                diagnostics.Add(diagnostic);
             }
             else
             {
                 foreach (var character in Name)
                 {
-                    if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                    if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                     {
                         var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeParameterName(
                             _parent.Name,
                             Name,
                             character);
 
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
                 }
             }
+
+            return diagnostics;
         }
     }
 }
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRequiredAttributeDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRequiredAttributeDescriptorBuilder.cs
index 9e1b98d10767fbfe5a7af00707d1043b161087d1..93f714d5ef08da04ddcc528cf58896e8e5772be2 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRequiredAttributeDescriptorBuilder.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRequiredAttributeDescriptorBuilder.cs
@@ -45,10 +45,10 @@ namespace Microsoft.AspNetCore.Razor.Language
 
         public RequiredAttributeDescriptor Build()
         {
-            var validationDiagnostics = Validate();
-            var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
+            var diagnostics = Validate();
             if (_diagnostics != null)
             {
+                diagnostics ??= new();
                 diagnostics.UnionWith(_diagnostics);
             }
 
@@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Razor.Language
                 Value,
                 ValueComparisonMode,
                 displayName,
-                diagnostics.ToArray(),
+                diagnostics?.ToArray() ?? Array.Empty<RazorDiagnostic>(),
                 new Dictionary<string, string>(Metadata));
 
             return rule;
@@ -71,39 +71,47 @@ namespace Microsoft.AspNetCore.Razor.Language
             return NameComparisonMode == RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch ? string.Concat(Name, "...") : Name;
         }
 
-        private IEnumerable<RazorDiagnostic> Validate()
+        private HashSet<RazorDiagnostic> Validate()
         {
+            HashSet<RazorDiagnostic> diagnostics = null;
+
             if (string.IsNullOrWhiteSpace(Name))
             {
                 var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace();
 
-                yield return diagnostic;
+                diagnostics ??= new();
+                diagnostics.Add(diagnostic);
             }
             else
             {
-                var name = Name;
+                var name = new StringSegment(Name);
                 var isDirectiveAttribute = this.IsDirectiveAttribute();
                 if (isDirectiveAttribute && name.StartsWith("@", StringComparison.Ordinal))
                 {
-                    name = name.Substring(1);
+                    name = name.Subsegment(1);
                 }
                 else if (isDirectiveAttribute)
                 {
                     var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredDirectiveAttributeName(GetDisplayName(), Name);
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
 
-                foreach (var character in name)
+                for (var i = 0; i < name.Length; i++)
                 {
-                    if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                    var character = name[i];
+                    if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                     {
                         var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName(Name, character);
 
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
                 }
             }
+
+            return diagnostics;
         }
     }
 }
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultTagMatchingRuleDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultTagMatchingRuleDescriptorBuilder.cs
index f17769422e18a234753ade4a75f1adb50c7ca629..944ecc800a4593055bf8150f01d1276240c0a69f 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultTagMatchingRuleDescriptorBuilder.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultTagMatchingRuleDescriptorBuilder.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
@@ -65,10 +65,10 @@ namespace Microsoft.AspNetCore.Razor.Language
 
         public TagMatchingRuleDescriptor Build()
         {
-            var validationDiagnostics = Validate();
-            var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
+            var diagnostics = Validate();
             if (_diagnostics != null)
             {
+                diagnostics ??= new();
                 diagnostics.UnionWith(_diagnostics);
             }
 
@@ -90,28 +90,32 @@ namespace Microsoft.AspNetCore.Razor.Language
                 TagStructure,
                 CaseSensitive,
                 requiredAttributes,
-                diagnostics.ToArray());
+                diagnostics?.ToArray() ?? Array.Empty<RazorDiagnostic>());
 
             return rule;
         }
 
-        private IEnumerable<RazorDiagnostic> Validate()
+        private HashSet<RazorDiagnostic> Validate()
         {
+            HashSet<RazorDiagnostic> diagnostics = null;
+
             if (string.IsNullOrWhiteSpace(TagName))
             {
                 var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedTagNameNullOrWhitespace();
 
-                yield return diagnostic;
+                diagnostics ??= new();
+                diagnostics.Add(diagnostic);
             }
             else if (TagName != TagHelperMatchingConventions.ElementCatchAllName)
             {
                 foreach (var character in TagName)
                 {
-                    if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                    if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                     {
                         var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedTagName(TagName, character);
 
-                        yield return diagnostic;
+                        diagnostics ??= new();
+                        diagnostics.Add(diagnostic);
                     }
                 }
             }
@@ -122,21 +126,25 @@ namespace Microsoft.AspNetCore.Razor.Language
                 {
                     var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedParentTagNameNullOrWhitespace();
 
-                    yield return diagnostic;
+                    diagnostics ??= new();
+                    diagnostics.Add(diagnostic);
                 }
                 else
                 {
                     foreach (var character in ParentTag)
                     {
-                        if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
+                        if (char.IsWhiteSpace(character) || HtmlConventions.IsInvalidNonWhitespaceHtmlCharacters(character))
                         {
                             var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedParentTagName(ParentTag, character);
 
-                            yield return diagnostic;
+                            diagnostics ??= new();
+                            diagnostics.Add(diagnostic);
                         }
                     }
                 }
             }
+
+            return diagnostics;
         }
 
         private void EnsureRequiredAttributeBuilders()
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/HtmlConventions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/HtmlConventions.cs
index 29e99c2df1c2565b91b068e490f8984508651c33..c73e8fc8e617be5ff50ced7ee154a8fd5824cee2 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/HtmlConventions.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/HtmlConventions.cs
@@ -1,8 +1,7 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
-using System.Collections.Generic;
 using System.Text.RegularExpressions;
 
 namespace Microsoft.AspNetCore.Razor.Language
@@ -10,6 +9,8 @@ namespace Microsoft.AspNetCore.Razor.Language
     public static class HtmlConventions
     {
         private const string HtmlCaseRegexReplacement = "-$1$2";
+        private static readonly char[] InvalidNonWhitespaceHtmlCharacters =
+            new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' };
 
         // This matches the following AFTER the start of the input string (MATCH).
         // Any letter/number followed by an uppercase letter then lowercase letter: 1(Aa), a(Aa), A(Aa)
@@ -21,8 +22,19 @@ namespace Microsoft.AspNetCore.Razor.Language
                 RegexOptions.None,
                 TimeSpan.FromMilliseconds(500));
 
-        internal static IReadOnlyCollection<char> InvalidNonWhitespaceHtmlCharacters { get; } = new List<char>(
-            new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' });
+
+        internal static bool IsInvalidNonWhitespaceHtmlCharacters(char testChar)
+        {
+            foreach (var c in InvalidNonWhitespaceHtmlCharacters)
+            {
+                if (c == testChar)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
 
         /// <summary>
         /// Converts from pascal/camel case to lower kebab-case.