Skip to content

Commit 37311b9

Browse files
authored
Lookup some types by name (#8110)
Lookup some types by name rather than using GetTypeByMetadataName
1 parent 6c36b27 commit 37311b9

File tree

6 files changed

+93
-186
lines changed

6 files changed

+93
-186
lines changed

src/Compiler/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentsApi.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public static class RenderFragmentOfT
6262
public const string Namespace = "Microsoft.AspNetCore.Components";
6363
public const string FullTypeName = Namespace + ".RenderFragment<>";
6464
public const string MetadataName = Namespace + ".RenderFragment`1";
65+
public const string DisplayName = Namespace + ".RenderFragment<TValue>";
6566
}
6667

6768
public static class RenderTreeBuilder
@@ -149,6 +150,7 @@ public static class EventCallback
149150
public static class EventCallbackOfT
150151
{
151152
public const string MetadataName = "Microsoft.AspNetCore.Components.EventCallback`1";
153+
public const string DisplayName = "Microsoft.AspNetCore.Components.EventCallback<TValue>";
152154
}
153155

154156
public static class EventCallbackFactory

src/Compiler/Microsoft.CodeAnalysis.Razor/src/ComponentDetectionConventions.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
#nullable disable
4+
#nullable enable
55

66
using System;
7+
using System.Linq;
78

89
namespace Microsoft.CodeAnalysis.Razor;
910

@@ -26,4 +27,22 @@ public static bool IsComponent(INamedTypeSymbol symbol, INamedTypeSymbol icompon
2627
!symbol.IsAbstract &&
2728
symbol.AllInterfaces.Contains(icomponentSymbol);
2829
}
30+
31+
public static bool IsComponent(INamedTypeSymbol symbol, string icomponentSymbolName)
32+
{
33+
if (symbol is null)
34+
{
35+
throw new ArgumentNullException(nameof(symbol));
36+
}
37+
38+
if (icomponentSymbolName is null)
39+
{
40+
throw new ArgumentNullException(nameof(icomponentSymbolName));
41+
}
42+
43+
return
44+
symbol.DeclaredAccessibility == Accessibility.Public &&
45+
!symbol.IsAbstract &&
46+
symbol.AllInterfaces.Any(s => s.HasFullName(icomponentSymbolName));
47+
}
2948
}

src/Compiler/Microsoft.CodeAnalysis.Razor/src/ComponentTagHelperDescriptorProvider.cs

Lines changed: 28 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,16 @@
44
#nullable disable
55

66
using System;
7-
using System.Text;
87
using System.Collections.Generic;
98
using System.Globalization;
109
using System.Linq;
1110
using Microsoft.AspNetCore.Razor.Language;
1211
using Microsoft.AspNetCore.Razor.Language.Components;
13-
using System.Runtime.CompilerServices;
1412

1513
namespace Microsoft.CodeAnalysis.Razor;
1614

1715
internal 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

Comments
 (0)