< Summary

Information
Class: NexusLabs.Needlr.Injection.SourceGen.Loaders.GeneratedAssemblyProvider
Assembly: NexusLabs.Needlr.Injection.SourceGen
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection.SourceGen/Loaders/GeneratedAssemblyProvider.cs
Line coverage
87%
Covered lines: 48
Uncovered lines: 7
Coverable lines: 55
Total lines: 117
Line coverage: 87.2%
Branch coverage
100%
Covered branches: 8
Total branches: 8
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
.ctor(...)100%6695.65%
AddAssembly()100%22100%
GetCandidateAssemblies()100%11100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection.SourceGen/Loaders/GeneratedAssemblyProvider.cs

#LineLine coverage
 1using System.Reflection;
 2
 3using NexusLabs.Needlr.Generators;
 4
 5namespace NexusLabs.Needlr.Injection.SourceGen.Loaders;
 6
 7/// <summary>
 8/// An assembly provider that derives assemblies from the generated TypeRegistry.
 9/// </summary>
 10/// <remarks>
 11/// <para>
 12/// When using source generation, the TypeRegistry contains all injectable types
 13/// and plugins discovered at compile time. Generated bootstraps also provide a
 14/// registry participant type so assemblies with no injectable types or plugins
 15/// remain available without runtime assembly scanning.
 16/// </para>
 17/// <para>
 18/// This provider should be used with <see cref="PluginFactories.GeneratedPluginFactory"/>
 19/// to ensure that all generated registry participants are included in plugin discovery
 20/// when runtime assembly metadata is available.
 21/// </para>
 22/// <para>
 23/// For assembly ordering, use <c>SyringeExtensions.OrderAssemblies</c> after configuring the Syringe.
 24/// </para>
 25/// </remarks>
 26[DoNotAutoRegister]
 27public sealed class GeneratedAssemblyProvider : IAssemblyProvider
 28{
 29    private readonly Lazy<IReadOnlyList<Assembly>> _lazyAssemblies;
 30
 31    /// <summary>
 32    /// Initializes a new instance of the <see cref="GeneratedAssemblyProvider"/> class.
 33    /// </summary>
 34    /// <param name="injectableTypesProvider">A function that returns the injectable types.</param>
 35    /// <param name="pluginTypesProvider">A function that returns the plugin types.</param>
 36    /// <remarks>
 37    /// This compatibility overload can derive assemblies only from injectable and plugin metadata.
 38    /// Use the three-argument overload when generated registry participant types are available.
 39    /// </remarks>
 40    public GeneratedAssemblyProvider(
 41        Func<IReadOnlyList<InjectableTypeInfo>> injectableTypesProvider,
 42        Func<IReadOnlyList<PluginTypeInfo>> pluginTypesProvider)
 043        : this(
 044            injectableTypesProvider,
 045            pluginTypesProvider,
 046            Array.Empty<Type>())
 47    {
 048    }
 49
 50    /// <summary>
 51    /// Initializes a new instance of the <see cref="GeneratedAssemblyProvider"/> class.
 52    /// </summary>
 53    /// <param name="injectableTypesProvider">A function that returns the injectable types.</param>
 54    /// <param name="pluginTypesProvider">A function that returns the plugin types.</param>
 55    /// <param name="registryParticipantTypes">
 56    /// Generated types whose assemblies identify every TypeRegistry participant.
 57    /// </param>
 58    /// <remarks>
 59    /// Assemblies represented by injectable and plugin metadata preserve their existing order.
 60    /// Marker-only participant assemblies are appended in registration order.
 61    /// </remarks>
 33262    public GeneratedAssemblyProvider(
 33263        Func<IReadOnlyList<InjectableTypeInfo>> injectableTypesProvider,
 33264        Func<IReadOnlyList<PluginTypeInfo>> pluginTypesProvider,
 33265        IReadOnlyList<Type> registryParticipantTypes)
 66    {
 33267        ArgumentNullException.ThrowIfNull(injectableTypesProvider);
 33268        ArgumentNullException.ThrowIfNull(pluginTypesProvider);
 33269        ArgumentNullException.ThrowIfNull(registryParticipantTypes);
 70
 33171        var registryParticipantTypeSnapshot = registryParticipantTypes.ToArray();
 33172        _lazyAssemblies = new(() =>
 33173        {
 33174            // In NativeAOT with reflection disabled, Type.Assembly can throw.
 33175            // Candidate assemblies are only a hint for reflection-based discovery.
 33176            // For source generation, the plugin/type registries already define the universe.
 33177            try
 33178            {
 32579                var assemblies = new List<Assembly>();
 32580                var seenAssemblies = new HashSet<Assembly>();
 33181
 10964482                foreach (var info in injectableTypesProvider())
 33183                {
 5449784                    AddAssembly(info.Type.Assembly);
 33185                }
 33186
 7255087                foreach (var info in pluginTypesProvider())
 33188                {
 3595089                    AddAssembly(info.PluginType.Assembly);
 33190                }
 33191
 110292                foreach (var registryParticipantType in registryParticipantTypeSnapshot)
 33193                {
 22694                    AddAssembly(registryParticipantType.Assembly);
 33195                }
 33196
 32597                return assemblies;
 33198
 33199                void AddAssembly(Assembly assembly)
 331100                {
 90673101                    if (seenAssemblies.Add(assembly))
 331102                    {
 1547103                        assemblies.Add(assembly);
 331104                    }
 90673105                }
 331106            }
 0107            catch (NotSupportedException)
 331108            {
 0109                return Array.Empty<Assembly>();
 331110            }
 656111        });
 331112    }
 113
 114    /// <inheritdoc />
 115    public IReadOnlyList<Assembly> GetCandidateAssemblies() =>
 628116        _lazyAssemblies.Value;
 117}