diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs index dc14b840fbe..caca023e27d 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs @@ -225,17 +225,21 @@ protected override bool IsCandidateType(INamedTypeSymbol types) => types.DeclaredAccessibility == Accessibility.Public && types.Name == "BindAttributes"; - protected override void Collect(IAssemblySymbol assembly, ICollection results, CancellationToken cancellationToken) + public override void Collect(TagHelperDescriptorProviderContext context, CancellationToken cancellationToken) { + // Overrides the outermost version of Collect as TagHelperCollector.Collect(context, token) + // caches results per assembly. This provider needs to operate on the full set of calculated + // descriptors to handle case #4. + // First, collect the initial set of tag helpers from this assembly. This calls // the Collect(INamedTypeSymbol, ...) overload below for cases #2 & #3. - base.Collect(assembly, results, cancellationToken); + base.Collect(context, cancellationToken); // Then, for case #4 we look at the tag helpers that were already created corresponding to components // and pattern match on properties. - using var componentBindTagHelpers = new PooledArrayBuilder(capacity: results.Count); + using var componentBindTagHelpers = new PooledArrayBuilder(capacity: context.Results.Count); - foreach (var tagHelper in results) + foreach (var tagHelper in context.Results) { cancellationToken.ThrowIfCancellationRequested(); @@ -244,7 +248,7 @@ protected override void Collect(IAssemblySymbol assembly, ICollection results, CancellationToken cancellationToken); - public void Collect(TagHelperDescriptorProviderContext context, CancellationToken cancellationToken) + public virtual void Collect(TagHelperDescriptorProviderContext context, CancellationToken cancellationToken) { if (_targetAssembly is not null) { - Collect(_targetAssembly, context.Results, cancellationToken); + CollectTagHelpersForAssembly(_targetAssembly, context, cancellationToken); } else { - Collect(_compilation.Assembly, context.Results, cancellationToken); + CollectTagHelpersForAssembly(_compilation.Assembly, context, cancellationToken); foreach (var reference in _compilation.References) { @@ -45,34 +45,41 @@ public void Collect(TagHelperDescriptorProviderContext context, CancellationToke if (_compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly) { - // Check to see if we already have tag helpers cached for this assembly - // and use the cached versions if we do. Roslyn shares PE assembly symbols - // across compilations, so this ensures that we don't produce new tag helpers - // for the same assemblies over and over again. + CollectTagHelpersForAssembly(assembly, context, cancellationToken); + } + } + } - var assemblySymbolData = SymbolCache.GetAssemblySymbolData(assembly); - if (!assemblySymbolData.MightContainTagHelpers) - { - continue; - } + return; - var includeDocumentation = context.IncludeDocumentation; - var excludeHidden = context.ExcludeHidden; + void CollectTagHelpersForAssembly(IAssemblySymbol assembly, TagHelperDescriptorProviderContext context, CancellationToken cancellationToken) + { + // Check to see if we already have tag helpers cached for this assembly + // and use the cached versions if we do. Roslyn shares PE assembly symbols + // across compilations, so this ensures that we don't produce new tag helpers + // for the same assemblies over and over again. - var cache = s_perAssemblyCaches.GetValue(assembly, static assembly => new Cache()); - if (!cache.TryGet(includeDocumentation, excludeHidden, out var tagHelpers)) - { - using var _ = ListPool.GetPooledObject(out var referenceTagHelpers); - Collect(assembly, referenceTagHelpers, cancellationToken); + var assemblySymbolData = SymbolCache.GetAssemblySymbolData(assembly); + if (!assemblySymbolData.MightContainTagHelpers) + { + return; + } - tagHelpers = cache.Add(referenceTagHelpers.ToArrayOrEmpty(), includeDocumentation, excludeHidden); - } + var includeDocumentation = context.IncludeDocumentation; + var excludeHidden = context.ExcludeHidden; - foreach (var tagHelper in tagHelpers) - { - context.Results.Add(tagHelper); - } - } + var cache = s_perAssemblyCaches.GetValue(assembly, static assembly => new Cache()); + if (!cache.TryGet(includeDocumentation, excludeHidden, out var tagHelpers)) + { + using var _ = ListPool.GetPooledObject(out var referenceTagHelpers); + Collect(assembly, referenceTagHelpers, cancellationToken); + + tagHelpers = cache.Add(referenceTagHelpers.ToArrayOrEmpty(), includeDocumentation, excludeHidden); + } + + foreach (var tagHelper in tagHelpers) + { + context.Results.Add(tagHelper); } } }