44#nullable disable
55
66using System ;
7- using System . Text ;
87using System . Collections . Generic ;
98using System . Globalization ;
109using System . Linq ;
1110using Microsoft . AspNetCore . Razor . Language ;
1211using Microsoft . AspNetCore . Razor . Language . Components ;
13- using System . Runtime . CompilerServices ;
1412
1513namespace Microsoft . CodeAnalysis . Razor ;
1614
1715internal class ComponentTagHelperDescriptorProvider : RazorEngineFeatureBase , ITagHelperDescriptorProvider
1816{
19- private static readonly SymbolDisplayFormat FullNameTypeDisplayFormat =
20- SymbolDisplayFormat . FullyQualifiedFormat
21- . WithGlobalNamespaceStyle ( SymbolDisplayGlobalNamespaceStyle . Omitted )
22- . WithMiscellaneousOptions ( SymbolDisplayFormat . FullyQualifiedFormat . MiscellaneousOptions & ( ~ SymbolDisplayMiscellaneousOptions . UseSpecialTypes ) ) ;
23-
2417 private static readonly SymbolDisplayFormat GloballyQualifiedFullNameTypeDisplayFormat =
2518 SymbolDisplayFormat . FullyQualifiedFormat
2619 . WithGlobalNamespaceStyle ( SymbolDisplayGlobalNamespaceStyle . Included )
@@ -44,10 +37,8 @@ public void Execute(TagHelperDescriptorProviderContext context)
4437 return ;
4538 }
4639
47- var symbols = ComponentSymbols . Create ( compilation ) ;
48-
4940 var types = new List < INamedTypeSymbol > ( ) ;
50- var visitor = new ComponentTypeVisitor ( symbols , types ) ;
41+ var visitor = new ComponentTypeVisitor ( types ) ;
5142
5243 var targetSymbol = context . Items . GetTargetSymbol ( ) ;
5344 if ( targetSymbol is not null )
@@ -73,23 +64,23 @@ public void Execute(TagHelperDescriptorProviderContext context)
7364 // Components have very simple matching rules.
7465 // 1. The type name (short) matches the tag name.
7566 // 2. The fully qualified name matches the tag name.
76- var shortNameMatchingDescriptor = CreateShortNameMatchingDescriptor ( symbols , type ) ;
67+ var shortNameMatchingDescriptor = CreateShortNameMatchingDescriptor ( type ) ;
7768 context . Results . Add ( shortNameMatchingDescriptor ) ;
78- var fullyQualifiedNameMatchingDescriptor = CreateFullyQualifiedNameMatchingDescriptor ( symbols , type ) ;
69+ var fullyQualifiedNameMatchingDescriptor = CreateFullyQualifiedNameMatchingDescriptor ( type ) ;
7970 context . Results . Add ( fullyQualifiedNameMatchingDescriptor ) ;
8071
8172 foreach ( var childContent in shortNameMatchingDescriptor . GetChildContentProperties ( ) )
8273 {
8374 // Synthesize a separate tag helper for each child content property that's declared.
84- context . Results . Add ( CreateChildContentDescriptor ( symbols , shortNameMatchingDescriptor , childContent ) ) ;
85- context . Results . Add ( CreateChildContentDescriptor ( symbols , fullyQualifiedNameMatchingDescriptor , childContent ) ) ;
75+ context . Results . Add ( CreateChildContentDescriptor ( shortNameMatchingDescriptor , childContent ) ) ;
76+ context . Results . Add ( CreateChildContentDescriptor ( fullyQualifiedNameMatchingDescriptor , childContent ) ) ;
8677 }
8778 }
8879 }
8980
90- private TagHelperDescriptor CreateShortNameMatchingDescriptor ( ComponentSymbols symbols , INamedTypeSymbol type )
81+ private TagHelperDescriptor CreateShortNameMatchingDescriptor ( INamedTypeSymbol type )
9182 {
92- var builder = CreateDescriptorBuilder ( symbols , type ) ;
83+ var builder = CreateDescriptorBuilder ( type ) ;
9384 builder . TagMatchingRule ( r =>
9485 {
9586 r . TagName = type . Name ;
@@ -98,9 +89,9 @@ private TagHelperDescriptor CreateShortNameMatchingDescriptor(ComponentSymbols s
9889 return builder . Build ( ) ;
9990 }
10091
101- private TagHelperDescriptor CreateFullyQualifiedNameMatchingDescriptor ( ComponentSymbols symbols , INamedTypeSymbol type )
92+ private TagHelperDescriptor CreateFullyQualifiedNameMatchingDescriptor ( INamedTypeSymbol type )
10293 {
103- var builder = CreateDescriptorBuilder ( symbols , type ) ;
94+ var builder = CreateDescriptorBuilder ( type ) ;
10495 var containingNamespace = type . ContainingNamespace . ToDisplayString ( ) ;
10596 var fullName = $ "{ containingNamespace } .{ type . Name } ";
10697 builder . TagMatchingRule ( r =>
@@ -112,14 +103,14 @@ private TagHelperDescriptor CreateFullyQualifiedNameMatchingDescriptor(Component
112103 return builder . Build ( ) ;
113104 }
114105
115- private TagHelperDescriptorBuilder CreateDescriptorBuilder ( ComponentSymbols symbols , INamedTypeSymbol type )
106+ private TagHelperDescriptorBuilder CreateDescriptorBuilder ( INamedTypeSymbol type )
116107 {
117- var typeName = type . ToDisplayString ( FullNameTypeDisplayFormat ) ;
108+ var typeName = type . ToDisplayString ( SymbolExtensions . FullNameTypeDisplayFormat ) ;
118109 var assemblyName = type . ContainingAssembly . Identity . Name ;
119110
120111 var builder = TagHelperDescriptorBuilder . Create ( ComponentMetadata . Component . TagHelperKind , typeName , assemblyName ) ;
121112 builder . SetTypeName ( typeName ) ;
122- builder . SetTypeNamespace ( type . ContainingNamespace . ToDisplayString ( FullNameTypeDisplayFormat ) ) ;
113+ builder . SetTypeNamespace ( type . ContainingNamespace . ToDisplayString ( SymbolExtensions . FullNameTypeDisplayFormat ) ) ;
123114 builder . SetTypeNameIdentifier ( type . Name ) ;
124115 builder . CaseSensitive = true ;
125116
@@ -133,7 +124,7 @@ private TagHelperDescriptorBuilder CreateDescriptorBuilder(ComponentSymbols symb
133124
134125 var cascadeGenericTypeAttributes = type
135126 . GetAttributes ( )
136- . Where ( a => SymbolEqualityComparer . Default . Equals ( a . AttributeClass , symbols . CascadingTypeParameterAttribute ) )
127+ . Where ( a => a . AttributeClass . HasFullName ( ComponentsApi . CascadingTypeParameterAttribute . MetadataName ) )
137128 . Select ( attribute => attribute . ConstructorArguments . FirstOrDefault ( ) . Value as string )
138129 . ToList ( ) ;
139130
@@ -154,14 +145,14 @@ private TagHelperDescriptorBuilder CreateDescriptorBuilder(ComponentSymbols symb
154145 builder . Documentation = xml ;
155146 }
156147
157- foreach ( var property in GetProperties ( symbols , type ) )
148+ foreach ( var property in GetProperties ( type ) )
158149 {
159150 if ( property . kind == PropertyKind . Ignored )
160151 {
161152 continue ;
162153 }
163154
164- CreateProperty ( builder , property . property , property . kind , symbols ) ;
155+ CreateProperty ( builder , property . property , property . kind ) ;
165156 }
166157
167158 if ( builder . BoundAttributes . Any ( a => a . IsParameterizedChildContentProperty ( ) ) &&
@@ -176,14 +167,14 @@ private TagHelperDescriptorBuilder CreateDescriptorBuilder(ComponentSymbols symb
176167 return builder ;
177168 }
178169
179- private void CreateProperty ( TagHelperDescriptorBuilder builder , IPropertySymbol property , PropertyKind kind , ComponentSymbols symbols )
170+ private void CreateProperty ( TagHelperDescriptorBuilder builder , IPropertySymbol property , PropertyKind kind )
180171 {
181172 builder . BindAttribute ( pb =>
182173 {
183174 pb . Name = property . Name ;
184- pb . TypeName = property . Type . ToDisplayString ( FullNameTypeDisplayFormat ) ;
175+ pb . TypeName = property . Type . ToDisplayString ( SymbolExtensions . FullNameTypeDisplayFormat ) ;
185176 pb . SetPropertyName ( property . Name ) ;
186- pb . IsEditorRequired = property . GetAttributes ( ) . Any ( a => a . AttributeClass . ToDisplayString ( ) == "Microsoft.AspNetCore.Components.EditorRequiredAttribute" ) ;
177+ pb . IsEditorRequired = property . GetAttributes ( ) . Any ( a => a . AttributeClass . HasFullName ( "Microsoft.AspNetCore.Components.EditorRequiredAttribute" ) ) ;
187178 pb . SetGloballyQualifiedTypeName ( property . Type . ToDisplayString ( GloballyQualifiedFullNameTypeDisplayFormat ) ) ;
188179 if ( kind == PropertyKind . Enum )
189180 {
@@ -377,7 +368,7 @@ private void CreateTypeParameterProperty(TagHelperDescriptorBuilder builder, ITy
377368 } ) ;
378369 }
379370
380- private TagHelperDescriptor CreateChildContentDescriptor ( ComponentSymbols symbols , TagHelperDescriptor component , BoundAttributeDescriptor attribute )
371+ private TagHelperDescriptor CreateChildContentDescriptor ( TagHelperDescriptor component , BoundAttributeDescriptor attribute )
381372 {
382373 var typeName = component . GetTypeName ( ) + "." + attribute . Name ;
383374 var assemblyName = component . AssemblyName ;
@@ -454,12 +445,12 @@ private void CreateContextParameter(TagHelperDescriptorBuilder builder, string c
454445 // - have the [Parameter] attribute
455446 // - have a setter, even if private
456447 // - are not indexers
457- private IEnumerable < ( IPropertySymbol property , PropertyKind kind ) > GetProperties ( ComponentSymbols symbols , INamedTypeSymbol type )
448+ private IEnumerable < ( IPropertySymbol property , PropertyKind kind ) > GetProperties ( INamedTypeSymbol type )
458449 {
459450 var properties = new Dictionary < string , ( IPropertySymbol , PropertyKind ) > ( StringComparer . Ordinal ) ;
460451 do
461452 {
462- if ( SymbolEqualityComparer . Default . Equals ( type , symbols . ComponentBase ) )
453+ if ( type . HasFullName ( ComponentsApi . ComponentBase . MetadataName ) )
463454 {
464455 // The ComponentBase base class doesn't have any [Parameter].
465456 // Bail out now to avoid walking through its many members, plus the members
@@ -512,7 +503,7 @@ private void CreateContextParameter(TagHelperDescriptorBuilder builder, string c
512503 kind = PropertyKind . Ignored ;
513504 }
514505
515- if ( ! property . GetAttributes ( ) . Any ( a => SymbolEqualityComparer . Default . Equals ( a . AttributeClass , symbols . ParameterAttribute ) ) )
506+ if ( ! property . GetAttributes ( ) . Any ( a => a . AttributeClass . HasFullName ( ComponentsApi . ParameterAttribute . MetadataName ) ) )
516507 {
517508 if ( property . IsOverride )
518509 {
@@ -530,28 +521,28 @@ private void CreateContextParameter(TagHelperDescriptorBuilder builder, string c
530521 kind = PropertyKind . Enum ;
531522 }
532523
533- if ( kind == PropertyKind . Default && SymbolEqualityComparer . Default . Equals ( property . Type , symbols . RenderFragment ) )
524+ if ( kind == PropertyKind . Default && property . Type . HasFullName ( ComponentsApi . RenderFragment . MetadataName ) )
534525 {
535526 kind = PropertyKind . ChildContent ;
536527 }
537528
538529 if ( kind == PropertyKind . Default &&
539530 property . Type is INamedTypeSymbol namedType &&
540531 namedType . IsGenericType &&
541- SymbolEqualityComparer . Default . Equals ( namedType . ConstructedFrom , symbols . RenderFragmentOfT ) )
532+ namedType . ConstructedFrom . HasFullName ( ComponentsApi . RenderFragmentOfT . DisplayName ) )
542533 {
543534 kind = PropertyKind . ChildContent ;
544535 }
545536
546- if ( kind == PropertyKind . Default && SymbolEqualityComparer . Default . Equals ( property . Type , symbols . EventCallback ) )
537+ if ( kind == PropertyKind . Default && property . Type . HasFullName ( ComponentsApi . EventCallback . MetadataName ) )
547538 {
548539 kind = PropertyKind . EventCallback ;
549540 }
550541
551542 if ( kind == PropertyKind . Default &&
552543 property . Type is INamedTypeSymbol namedType2 &&
553544 namedType2 . IsGenericType &&
554- SymbolEqualityComparer . Default . Equals ( namedType2 . ConstructedFrom , symbols . EventCallbackOfT ) )
545+ namedType2 . ConstructedFrom . HasFullName ( ComponentsApi . EventCallbackOfT . DisplayName ) )
555546 {
556547 kind = PropertyKind . EventCallback ;
557548 }
@@ -581,108 +572,18 @@ private enum PropertyKind
581572 EventCallback ,
582573 }
583574
584- private class ComponentSymbols
585- {
586- public static ComponentSymbols Create ( Compilation compilation )
587- {
588- // We find a bunch of important and fundamental types here that are needed to discover
589- // components. If one of these isn't defined then we just bail, because the results will
590- // be unpredictable.
591- var symbols = new ComponentSymbols ( ) ;
592-
593- symbols . ComponentBase = compilation . GetTypeByMetadataName ( ComponentsApi . ComponentBase . MetadataName ) ;
594- if ( symbols . ComponentBase == null )
595- {
596- // No definition for ComponentBase, nothing to do.
597- return null ;
598- }
599-
600- symbols . IComponent = compilation . GetTypeByMetadataName ( ComponentsApi . IComponent . MetadataName ) ;
601- if ( symbols . IComponent == null )
602- {
603- // No definition for IComponent, nothing to do.
604- return null ;
605- }
606-
607- symbols . ParameterAttribute = compilation . GetTypeByMetadataName ( ComponentsApi . ParameterAttribute . MetadataName ) ;
608- if ( symbols . ParameterAttribute == null )
609- {
610- // No definition for [Parameter], nothing to do.
611- return null ;
612- }
613-
614- symbols . RenderFragment = compilation . GetTypeByMetadataName ( ComponentsApi . RenderFragment . MetadataName ) ;
615- if ( symbols . RenderFragment == null )
616- {
617- // No definition for RenderFragment, nothing to do.
618- return null ;
619- }
620-
621- symbols . RenderFragmentOfT = compilation . GetTypeByMetadataName ( ComponentsApi . RenderFragmentOfT . MetadataName ) ;
622- if ( symbols . RenderFragmentOfT == null )
623- {
624- // No definition for RenderFragment<T>, nothing to do.
625- return null ;
626- }
627-
628- symbols . EventCallback = compilation . GetTypeByMetadataName ( ComponentsApi . EventCallback . MetadataName ) ;
629- if ( symbols . EventCallback == null )
630- {
631- // No definition for EventCallback, nothing to do.
632- return null ;
633- }
634-
635- symbols . EventCallbackOfT = compilation . GetTypeByMetadataName ( ComponentsApi . EventCallbackOfT . MetadataName ) ;
636- if ( symbols . EventCallbackOfT == null )
637- {
638- // No definition for EventCallback<T>, nothing to do.
639- return null ;
640- }
641-
642- symbols . CascadingTypeParameterAttribute = compilation . GetTypeByMetadataName ( ComponentsApi . CascadingTypeParameterAttribute . MetadataName ) ;
643- if ( symbols . CascadingTypeParameterAttribute == null )
644- {
645- // No definition for [CascadingTypeParameter]. For back-compat, just don't activate this feature.
646- }
647-
648- return symbols ;
649- }
650-
651- private ComponentSymbols ( )
652- {
653- }
654-
655- public INamedTypeSymbol ComponentBase { get ; private set ; }
656-
657- public INamedTypeSymbol IComponent { get ; private set ; }
658-
659- public INamedTypeSymbol ParameterAttribute { get ; private set ; }
660-
661- public INamedTypeSymbol RenderFragment { get ; private set ; }
662-
663- public INamedTypeSymbol RenderFragmentOfT { get ; private set ; }
664-
665- public INamedTypeSymbol EventCallback { get ; private set ; }
666-
667- public INamedTypeSymbol EventCallbackOfT { get ; private set ; }
668-
669- public INamedTypeSymbol CascadingTypeParameterAttribute { get ; private set ; }
670- }
671-
672575 private class ComponentTypeVisitor : SymbolVisitor
673576 {
674- private readonly ComponentSymbols _symbols ;
675577 private readonly List < INamedTypeSymbol > _results ;
676578
677- public ComponentTypeVisitor ( ComponentSymbols symbols , List < INamedTypeSymbol > results )
579+ public ComponentTypeVisitor ( List < INamedTypeSymbol > results )
678580 {
679- _symbols = symbols ;
680581 _results = results ;
681582 }
682583
683584 public override void VisitNamedType ( INamedTypeSymbol symbol )
684585 {
685- if ( IsComponent ( symbol ) )
586+ if ( ComponentDetectionConventions . IsComponent ( symbol , ComponentsApi . IComponent . MetadataName ) )
686587 {
687588 _results . Add ( symbol ) ;
688589 }
@@ -705,16 +606,5 @@ public override void VisitAssembly(IAssemblySymbol symbol)
705606 Visit ( symbol . GlobalNamespace ) ;
706607 }
707608 }
708-
709- internal bool IsComponent ( INamedTypeSymbol symbol )
710- {
711- if ( _symbols == null )
712- {
713- return false ;
714- }
715-
716- var isComponent = ComponentDetectionConventions . IsComponent ( symbol , _symbols . IComponent ) ;
717- return isComponent ;
718- }
719609 }
720610}
0 commit comments