< Summary

Information
Class: NexusLabs.Needlr.Generators.TypeRegistryGenerator
Assembly: NexusLabs.Needlr.Generators
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/TypeRegistryGenerator.cs
Line coverage
94%
Covered lines: 506
Uncovered lines: 29
Coverable lines: 535
Total lines: 879
Line coverage: 94.5%
Branch coverage
85%
Covered branches: 237
Total branches: 276
Branch coverage: 85.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Initialize(...)98.27%5858100%
GetBreadcrumbLevel(...)100%88100%
GetProjectDirectory(...)50%4475%
GetDiagnosticOptions(...)100%11100%
ShouldExportGraph(...)100%44100%
IsAotProject(...)100%88100%
GetAttributeInfoFromCompilation(...)83.33%332475%
DiscoverTypes(...)96.42%2828100%
CollectTypesFromAssembly(...)77.04%14712288.16%
GenerateTypeRegistrySource(...)100%1010100%
GenerateRegisterOptionsMethod(...)70%101089.47%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/TypeRegistryGenerator.cs

#LineLine coverage
 1using Microsoft.CodeAnalysis;
 2using Microsoft.CodeAnalysis.Text;
 3using NexusLabs.Needlr.Generators.Helpers;
 4using NexusLabs.Needlr.Generators.Models;
 5using System.Text;
 6
 7namespace NexusLabs.Needlr.Generators;
 8
 9/// <summary>
 10/// Incremental source generator that produces a compile-time type registry
 11/// for dependency injection, eliminating runtime reflection.
 12/// </summary>
 13[Generator(LanguageNames.CSharp)]
 14public sealed class TypeRegistryGenerator : IIncrementalGenerator
 15{
 16    private const string GenerateTypeRegistryAttributeName = "NexusLabs.Needlr.Generators.GenerateTypeRegistryAttribute"
 17
 18    public void Initialize(IncrementalGeneratorInitializationContext context)
 19    {
 20        // Combine compilation with analyzer config options to read MSBuild properties
 46521        var compilationAndOptions = context.CompilationProvider
 46522            .Combine(context.AnalyzerConfigOptionsProvider);
 23
 24        // ForAttributeWithMetadataName doesn't work for assembly-level attributes.
 25        // Instead, we register directly on the compilation provider and check
 26        // compilation.Assembly.GetAttributes() for [GenerateTypeRegistry].
 46527        context.RegisterSourceOutput(compilationAndOptions, static (spc, source) =>
 46528        {
 46529            var (compilation, configOptions) = source;
 46530
 46531            var attributeInfo = GetAttributeInfoFromCompilation(compilation);
 46532            if (attributeInfo == null)
 133                return;
 46534
 46435            var info = attributeInfo.Value;
 46436            var assemblyName = compilation.AssemblyName ?? "Generated";
 46537
 46538            // Read breadcrumb level from MSBuild property
 46439            var breadcrumbLevel = GetBreadcrumbLevel(configOptions);
 46440            var projectDirectory = GetProjectDirectory(configOptions);
 46441            var breadcrumbs = new BreadcrumbWriter(breadcrumbLevel);
 46542
 46543            // Check if this is an AOT project
 46444            var isAotProject = IsAotProject(configOptions);
 46545
 46446            var discoveryResult = DiscoverTypes(
 46447                compilation,
 46448                info.NamespacePrefixes,
 46449                info.ExcludeNamespacePrefixes,
 46450                info.IncludeSelf);
 46551
 46552            // Discover referenced assemblies with [GenerateTypeRegistry] for forced loading.
 46553            // Done early so the empty-result check below can include this in its decision.
 46554            // Note: Order of force-loading doesn't matter; ordering is applied at service registration time
 46455            var referencedAssemblies = AssemblyDiscoveryHelper.DiscoverReferencedAssembliesWithTypeRegistry(compilation)
 256                .OrderBy(a => a, StringComparer.OrdinalIgnoreCase)
 46457                .ToList();
 46558
 46559            // Nothing was discovered: no injectable types, factories, providers, options,
 46560            // interceptors, hosted services, plugins, no referenced assemblies to force-load,
 46561            // no inaccessible type errors, and no missing TypeRegistry warnings.
 46462            var nothingDiscovered =
 46463                discoveryResult.InjectableTypes.Count == 0 &&
 46464                discoveryResult.PluginTypes.Count == 0 &&
 46465                discoveryResult.Decorators.Count == 0 &&
 46466                discoveryResult.InterceptedServices.Count == 0 &&
 46467                discoveryResult.Factories.Count == 0 &&
 46468                discoveryResult.Options.Count == 0 &&
 46469                discoveryResult.HttpClients.Count == 0 &&
 46470                discoveryResult.HostedServices.Count == 0 &&
 46471                discoveryResult.Providers.Count == 0 &&
 46472                discoveryResult.InaccessibleTypes.Count == 0 &&
 46473                discoveryResult.MissingTypeRegistryPlugins.Count == 0 &&
 46474                referencedAssemblies.Count == 0;
 46575
 46576            // A type-less assembly that still carries [GenerateTypeRegistry] (guaranteed here by the
 46577            // attributeInfo guard above) is a declared Needlr participant. Consumers force-load
 46578            // typeof({Assembly}.Generated.TypeRegistry) for every attribute-carrying referenced
 46579            // assembly, so emitting nothing makes those consumers fail to compile with CS0234. Emit
 46580            // a minimal registry instead. It depends only on the attributes package (never the
 46581            // injection packages), so it compiles whether or not this assembly references them — a
 46582            // domain, contracts, or documentation-only project participates without being forced to
 46583            // take a dependency it would not otherwise have.
 46484            if (nothingDiscovered)
 46585            {
 786                var emptyRegistrySource = CodeGen.EmptyTypeRegistryCodeGenerator.GenerateTypeRegistrySource(assemblyName
 787                spc.AddSource("TypeRegistry.g.cs", SourceText.From(emptyRegistrySource, Encoding.UTF8));
 46588
 789                var emptyBootstrapSource = CodeGen.EmptyTypeRegistryCodeGenerator.GenerateBootstrapSource(assemblyName, 
 790                spc.AddSource("NeedlrSourceGenBootstrap.g.cs", SourceText.From(emptyBootstrapSource, Encoding.UTF8));
 791                return;
 46592            }
 46593
 46594            // Report errors for inaccessible internal types in referenced assemblies
 555295            foreach (var inaccessibleType in discoveryResult.InaccessibleTypes)
 46596            {
 231997                spc.ReportDiagnostic(Diagnostic.Create(
 231998                    DiagnosticDescriptors.InaccessibleInternalType,
 231999                    Location.None,
 2319100                    inaccessibleType.TypeName,
 2319101                    inaccessibleType.AssemblyName));
 465102            }
 465103
 465104            // Report errors for referenced assemblies with internal plugin types but no [GenerateTypeRegistry]
 916105            foreach (var missingPlugin in discoveryResult.MissingTypeRegistryPlugins)
 465106            {
 1107                spc.ReportDiagnostic(Diagnostic.Create(
 1108                    DiagnosticDescriptors.MissingGenerateTypeRegistryAttribute,
 1109                    Location.None,
 1110                    missingPlugin.AssemblyName,
 1111                    missingPlugin.TypeName));
 465112            }
 465113
 465114            // NDLRGEN020: Previously reported error if [Options] used in AOT project
 465115            // Now removed for parity - we generate best-effort code and let unsupported
 465116            // types fail at runtime (matching non-AOT ConfigurationBinder behavior)
 465117
 465118            // NDLRGEN021: Report warning for non-partial positional records
 1083119            foreach (var opt in discoveryResult.Options.Where(o => o.IsNonPartialPositionalRecord))
 465120            {
 2121                spc.ReportDiagnostic(Diagnostic.Create(
 2122                    DiagnosticDescriptors.PositionalRecordMustBePartial,
 2123                    Location.None,
 2124                    opt.TypeName));
 465125            }
 465126
 465127            // NDLRGEN022: Detect disposable captive dependencies using inferred lifetimes
 457128            CaptiveDependencyAnalyzer.ReportDisposableCaptiveDependencies(spc, discoveryResult);
 465129
 457130            var sourceText = GenerateTypeRegistrySource(discoveryResult, assemblyName, breadcrumbs, projectDirectory, is
 457131            spc.AddSource("TypeRegistry.g.cs", SourceText.From(sourceText, Encoding.UTF8));
 465132
 457133            var bootstrapText = CodeGen.BootstrapCodeGenerator.GenerateModuleInitializerBootstrapSource(assemblyName, re
 457134            spc.AddSource("NeedlrSourceGenBootstrap.g.cs", SourceText.From(bootstrapText, Encoding.UTF8));
 465135
 465136            // Generate interceptor proxy classes if any were discovered
 457137            if (discoveryResult.InterceptedServices.Count > 0)
 465138            {
 14139                var interceptorProxiesText = CodeGen.InterceptorCodeGenerator.GenerateInterceptorProxiesSource(discovery
 14140                spc.AddSource("InterceptorProxies.g.cs", SourceText.From(interceptorProxiesText, Encoding.UTF8));
 465141            }
 465142
 465143            // Generate factory classes if any were discovered
 457144            if (discoveryResult.Factories.Count > 0)
 465145            {
 24146                var factoriesText = CodeGen.FactoryCodeGenerator.GenerateFactoriesSource(discoveryResult.Factories, asse
 24147                spc.AddSource("Factories.g.cs", SourceText.From(factoriesText, Encoding.UTF8));
 465148            }
 465149
 465150            // Generate provider classes if any were discovered
 457151            if (discoveryResult.Providers.Count > 0)
 465152            {
 465153                // Interface-based providers go in the Generated namespace
 35154                var interfaceProviders = discoveryResult.Providers.Where(p => p.IsInterface).ToList();
 17155                if (interfaceProviders.Count > 0)
 465156                {
 11157                    var providersText = CodeGen.ProviderCodeGenerator.GenerateProvidersSource(interfaceProviders, assemb
 11158                    spc.AddSource("Providers.g.cs", SourceText.From(providersText, Encoding.UTF8));
 465159                }
 465160
 465161                // Shorthand class providers need to be generated in their original namespace
 35162                var classProviders = discoveryResult.Providers.Where(p => !p.IsInterface && p.IsPartial).ToList();
 46163                foreach (var provider in classProviders)
 465164                {
 6165                    var providerText = CodeGen.ProviderCodeGenerator.GenerateShorthandProviderSource(provider, assemblyN
 6166                    spc.AddSource($"Provider.{provider.SimpleTypeName}.g.cs", SourceText.From(providerText, Encoding.UTF
 465167                }
 465168            }
 465169
 465170            // Generate options validator classes if any have validation methods
 622171            var optionsWithValidators = discoveryResult.Options.Where(o => o.HasValidatorMethod).ToList();
 457172            if (optionsWithValidators.Count > 0)
 465173            {
 18174                var validatorsText = CodeGen.OptionsCodeGenerator.GenerateOptionsValidatorsSource(optionsWithValidators,
 18175                spc.AddSource("OptionsValidators.g.cs", SourceText.From(validatorsText, Encoding.UTF8));
 465176            }
 465177
 465178            // Generate DataAnnotations validator classes if any have DataAnnotation attributes
 622179            var optionsWithDataAnnotations = discoveryResult.Options.Where(o => o.HasDataAnnotations).ToList();
 457180            if (optionsWithDataAnnotations.Count > 0)
 465181            {
 18182                var dataAnnotationsValidatorsText = CodeGen.OptionsCodeGenerator.GenerateDataAnnotationsValidatorsSource
 18183                spc.AddSource("OptionsDataAnnotationsValidators.g.cs", SourceText.From(dataAnnotationsValidatorsText, En
 465184            }
 465185
 465186            // Generate parameterless constructors for partial positional records with [Options]
 622187            var optionsNeedingConstructors = discoveryResult.Options.Where(o => o.NeedsGeneratedConstructor).ToList();
 457188            if (optionsNeedingConstructors.Count > 0)
 465189            {
 7190                var constructorsText = CodeGen.OptionsCodeGenerator.GeneratePositionalRecordConstructorsSource(optionsNe
 7191                spc.AddSource("OptionsConstructors.g.cs", SourceText.From(constructorsText, Encoding.UTF8));
 465192            }
 465193
 465194            // Generate ServiceCatalog for runtime introspection
 457195            var catalogText = CodeGen.ServiceCatalogCodeGenerator.GenerateServiceCatalogSource(discoveryResult, assembly
 457196            spc.AddSource("ServiceCatalog.g.cs", SourceText.From(catalogText, Encoding.UTF8));
 465197
 465198            // Generate diagnostic output files if configured
 457199            var diagnosticOptions = GetDiagnosticOptions(configOptions);
 457200            if (diagnosticOptions.Enabled)
 465201            {
 95202                var referencedAssemblyTypes = AssemblyDiscoveryHelper.DiscoverReferencedAssemblyTypesForDiagnostics(comp
 95203                var diagnosticsText = DiagnosticsGenerator.GenerateDiagnosticsSource(discoveryResult, assemblyName, proj
 95204                spc.AddSource("NeedlrDiagnostics.g.cs", SourceText.From(diagnosticsText, Encoding.UTF8));
 465205            }
 465206
 465207            // Generate IDE graph export if configured
 457208            if (ShouldExportGraph(configOptions))
 465209            {
 465210                // Discover types from referenced assemblies with [GenerateTypeRegistry] for graph inclusion
 4211                var referencedAssemblyTypesForGraph = AssemblyDiscoveryHelper.DiscoverReferencedAssemblyTypesForGraph(co
 465212
 4213                var graphJson = Export.GraphExporter.GenerateGraphJson(
 4214                    discoveryResult,
 4215                    assemblyName,
 4216                    projectDirectory,
 4217                    diagnostics: null,
 4218                    referencedAssemblyTypes: referencedAssemblyTypesForGraph);
 465219
 465220                // Embed graph as a comment in a generated file so it's accessible
 465221                // The actual JSON is written to obj folder via the generated code
 4222                var graphSourceText = Export.GraphExporter.GenerateGraphExportSource(graphJson, assemblyName, breadcrumb
 4223                spc.AddSource("NeedlrGraph.g.cs", SourceText.From(graphSourceText, Encoding.UTF8));
 465224            }
 922225        });
 465226    }
 227
 228    private static BreadcrumbLevel GetBreadcrumbLevel(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider c
 229    {
 464230        if (configOptions.GlobalOptions.TryGetValue("build_property.NeedlrBreadcrumbLevel", out var levelStr) &&
 464231            !string.IsNullOrWhiteSpace(levelStr))
 232        {
 259233            if (levelStr.Equals("None", StringComparison.OrdinalIgnoreCase))
 17234                return BreadcrumbLevel.None;
 242235            if (levelStr.Equals("Verbose", StringComparison.OrdinalIgnoreCase))
 28236                return BreadcrumbLevel.Verbose;
 237        }
 238
 239        // Default to Minimal
 419240        return BreadcrumbLevel.Minimal;
 241    }
 242
 243    private static string? GetProjectDirectory(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider configOp
 244    {
 245        // Try to get the project directory from MSBuild properties
 464246        if (configOptions.GlobalOptions.TryGetValue("build_property.ProjectDir", out var projectDir) &&
 464247            !string.IsNullOrWhiteSpace(projectDir))
 248        {
 0249            return projectDir.TrimEnd('/', '\\');
 250        }
 251
 464252        return null;
 253    }
 254
 255    private static DiagnosticOptions GetDiagnosticOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvid
 256    {
 457257        configOptions.GlobalOptions.TryGetValue("build_property.NeedlrDiagnostics", out var enabled);
 457258        configOptions.GlobalOptions.TryGetValue("build_property.NeedlrDiagnosticsPath", out var outputPath);
 457259        configOptions.GlobalOptions.TryGetValue("build_property.NeedlrDiagnosticsFilter", out var filter);
 260
 457261        return DiagnosticOptions.Parse(enabled, outputPath, filter);
 262    }
 263
 264    /// <summary>
 265    /// Checks if the IDE graph export is enabled.
 266    /// </summary>
 267    private static bool ShouldExportGraph(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider configOptions
 268    {
 269        // Export graph is disabled by default
 270        // Enable with NeedlrExportGraph=true in project file
 457271        if (configOptions.GlobalOptions.TryGetValue("build_property.NeedlrExportGraph", out var exportGraph) &&
 457272            exportGraph.Equals("true", StringComparison.OrdinalIgnoreCase))
 273        {
 4274            return true;
 275        }
 453276        return false;
 277    }
 278
 279    /// <summary>
 280    /// Checks if the project is configured for AOT compilation.
 281    /// Returns true if either PublishAot or IsAotCompatible is set to true.
 282    /// </summary>
 283    private static bool IsAotProject(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider configOptions)
 284    {
 464285        if (configOptions.GlobalOptions.TryGetValue("build_property.PublishAot", out var publishAot) &&
 464286            publishAot.Equals("true", StringComparison.OrdinalIgnoreCase))
 287        {
 79288            return true;
 289        }
 290
 385291        if (configOptions.GlobalOptions.TryGetValue("build_property.IsAotCompatible", out var isAotCompatible) &&
 385292            isAotCompatible.Equals("true", StringComparison.OrdinalIgnoreCase))
 293        {
 1294            return true;
 295        }
 296
 384297        return false;
 298    }
 299
 300    private static AttributeInfo? GetAttributeInfoFromCompilation(Compilation compilation)
 301    {
 302        // Get assembly-level attributes directly from the compilation
 1394303        foreach (var attribute in compilation.Assembly.GetAttributes())
 304        {
 464305            var attrClassName = attribute.AttributeClass?.ToDisplayString();
 306
 307            // Check if this is our attribute (various name format possibilities)
 464308            if (attrClassName != GenerateTypeRegistryAttributeName)
 309                continue;
 310
 464311            string[]? namespacePrefixes = null;
 464312            string[]? excludeNamespacePrefixes = null;
 464313            var includeSelf = true;
 314
 1104315            foreach (var namedArg in attribute.NamedArguments)
 316            {
 88317                switch (namedArg.Key)
 318                {
 319                    case "IncludeNamespacePrefixes":
 78320                        if (!namedArg.Value.IsNull && namedArg.Value.Values.Length > 0)
 321                        {
 78322                            namespacePrefixes = namedArg.Value.Values
 79323                                .Where(v => v.Value is string)
 79324                                .Select(v => (string)v.Value!)
 78325                                .ToArray();
 326                        }
 78327                        break;
 328
 329                    case "ExcludeNamespacePrefixes":
 0330                        if (!namedArg.Value.IsNull && namedArg.Value.Values.Length > 0)
 331                        {
 0332                            excludeNamespacePrefixes = namedArg.Value.Values
 0333                                .Where(v => v.Value is string)
 0334                                .Select(v => (string)v.Value!)
 0335                                .ToArray();
 336                        }
 0337                        break;
 338
 339                    case "IncludeSelf":
 10340                        if (namedArg.Value.Value is bool selfValue)
 341                        {
 10342                            includeSelf = selfValue;
 343                        }
 344                        break;
 345                }
 346            }
 347
 464348            return new AttributeInfo(namespacePrefixes, excludeNamespacePrefixes, includeSelf);
 349        }
 350
 1351        return null;
 352    }
 353
 354    private static DiscoveryResult DiscoverTypes(
 355        Compilation compilation,
 356        string[]? namespacePrefixes,
 357        string[]? excludeNamespacePrefixes,
 358        bool includeSelf)
 359    {
 464360        var injectableTypes = new List<DiscoveredType>();
 464361        var pluginTypes = new List<DiscoveredPlugin>();
 464362        var decorators = new List<DiscoveredDecorator>();
 464363        var openDecorators = new List<DiscoveredOpenDecorator>();
 464364        var interceptedServices = new List<DiscoveredInterceptedService>();
 464365        var factories = new List<DiscoveredFactory>();
 464366        var options = new List<DiscoveredOptions>();
 464367        var hostedServices = new List<DiscoveredHostedService>();
 464368        var providers = new List<DiscoveredProvider>();
 464369        var httpClients = new List<DiscoveredHttpClient>();
 464370        var inaccessibleTypes = new List<InaccessibleType>();
 464371        var prefixList = namespacePrefixes?.ToList();
 464372        var excludePrefixList = excludeNamespacePrefixes?.ToList();
 373
 374        // Compute the generated namespace for the current assembly
 464375        var currentAssemblyName = compilation.Assembly.Name;
 464376        var safeAssemblyName = GeneratorHelpers.SanitizeIdentifier(currentAssemblyName);
 464377        var generatedNamespace = $"{safeAssemblyName}.Generated";
 378
 379        // Collect types from the current compilation if includeSelf is true
 464380        if (includeSelf)
 381        {
 463382            CollectTypesFromAssembly(compilation.Assembly, prefixList, excludePrefixList, injectableTypes, pluginTypes, 
 383        }
 384
 385        // Collect types from all referenced assemblies
 157678386        foreach (var reference in compilation.References)
 387        {
 78375388            if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assemblySymbol)
 389            {
 390                // Skip assemblies that already have [GenerateTypeRegistry] — those assemblies
 391                // register their own types at runtime via their own TypeRegistry and cascade
 392                // loading. Scanning them here would trigger false NDLRGEN001 errors for their
 393                // internal types.
 78188394                if (TypeDiscoveryHelper.HasGenerateTypeRegistryAttribute(assemblySymbol))
 395                    continue;
 396
 397                // For referenced assemblies, they use their own generated namespace
 78169398                var refSafeAssemblyName = GeneratorHelpers.SanitizeIdentifier(assemblySymbol.Name);
 78169399                var refGeneratedNamespace = $"{refSafeAssemblyName}.Generated";
 78169400                CollectTypesFromAssembly(assemblySymbol, prefixList, excludePrefixList, injectableTypes, pluginTypes, de
 401            }
 402        }
 403
 404        // Expand open generic decorators into closed decorator registrations
 464405        if (openDecorators.Count > 0)
 406        {
 6407            CodeGen.DecoratorsCodeGenerator.ExpandOpenDecorators(injectableTypes, openDecorators, decorators);
 408        }
 409
 410        // Filter out nested options types (types used as properties in other options types)
 464411        if (options.Count > 1)
 412        {
 19413            options = OptionsDiscoveryHelper.FilterNestedOptions(options, compilation);
 414        }
 415
 416        // Check for referenced assemblies with internal plugin types but no [GenerateTypeRegistry]
 464417        var missingTypeRegistryPlugins = new List<MissingTypeRegistryPlugin>();
 157678418        foreach (var reference in compilation.References)
 419        {
 78375420            if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assemblySymbol)
 421            {
 422                // Skip assemblies that already have [GenerateTypeRegistry]
 78188423                if (TypeDiscoveryHelper.HasGenerateTypeRegistryAttribute(assemblySymbol))
 424                    continue;
 425
 426                // Look for internal types that implement Needlr plugin interfaces
 3830500427                foreach (var typeSymbol in TypeDiscoveryHelper.GetAllTypes(assemblySymbol.GlobalNamespace))
 428                {
 1837081429                    if (!TypeDiscoveryHelper.IsInternalOrLessAccessible(typeSymbol))
 430                        continue;
 431
 87423432                    if (!TypeDiscoveryHelper.ImplementsNeedlrPluginInterface(typeSymbol))
 433                        continue;
 434
 435                    // This is an internal plugin type in an assembly without [GenerateTypeRegistry]
 1436                    var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 1437                    missingTypeRegistryPlugins.Add(new MissingTypeRegistryPlugin(typeName, assemblySymbol.Name));
 438                }
 439            }
 440        }
 441
 464442        return new DiscoveryResult(injectableTypes, pluginTypes, decorators, inaccessibleTypes, missingTypeRegistryPlugi
 443    }
 444
 445    private static void CollectTypesFromAssembly(
 446        IAssemblySymbol assembly,
 447        IReadOnlyList<string>? namespacePrefixes,
 448        IReadOnlyList<string>? excludeNamespacePrefixes,
 449        List<DiscoveredType> injectableTypes,
 450        List<DiscoveredPlugin> pluginTypes,
 451        List<DiscoveredDecorator> decorators,
 452        List<DiscoveredOpenDecorator> openDecorators,
 453        List<DiscoveredInterceptedService> interceptedServices,
 454        List<DiscoveredFactory> factories,
 455        List<DiscoveredOptions> options,
 456        List<DiscoveredHostedService> hostedServices,
 457        List<DiscoveredProvider> providers,
 458        List<DiscoveredHttpClient> httpClients,
 459        List<InaccessibleType> inaccessibleTypes,
 460        Compilation compilation,
 461        bool isCurrentAssembly,
 462        string generatedNamespace)
 463    {
 3834064464        foreach (var typeSymbol in TypeDiscoveryHelper.GetAllTypes(assembly.GlobalNamespace))
 465        {
 1838400466            if (!TypeDiscoveryHelper.MatchesNamespacePrefix(typeSymbol, namespacePrefixes))
 467                continue;
 468
 1530574469            if (TypeDiscoveryHelper.MatchesExclusionFilter(typeSymbol, excludeNamespacePrefixes))
 470                continue;
 471
 472            // .NET MAUI per-platform application entry points are framework-owned and carry
 473            // platform-generated interop members that are inaccessible from generated code.
 474            // Scanning them breaks the head build, so skip them before any discovery path runs.
 1530574475            if (TypeDiscoveryHelper.IsMauiPlatformEntryType(typeSymbol))
 476                continue;
 477
 478            // For referenced assemblies, check if the type would be registerable but is inaccessible
 1530570479            if (!isCurrentAssembly && TypeDiscoveryHelper.IsInternalOrLessAccessible(typeSymbol))
 480            {
 481                // Check if this type would have been registered if it were accessible
 73310482                if (TypeDiscoveryHelper.WouldBeInjectableIgnoringAccessibility(typeSymbol) ||
 73310483                    TypeDiscoveryHelper.WouldBePluginIgnoringAccessibility(typeSymbol, compilation.Assembly))
 484                {
 2319485                    var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 2319486                    inaccessibleTypes.Add(new InaccessibleType(typeName, assembly.Name));
 487                }
 2319488                continue; // Skip further processing for inaccessible types
 489            }
 490
 491            // Check for [Options] attribute
 1457260492            if (OptionsAttributeHelper.HasOptionsAttribute(typeSymbol))
 493            {
 167494                var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 167495                var optionsAttrs = OptionsAttributeHelper.GetOptionsAttributes(typeSymbol);
 167496                var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 497
 498                // Detect positional record (record with primary constructor parameters)
 167499                var positionalRecordInfo = OptionsDiscoveryHelper.DetectPositionalRecord(typeSymbol);
 500
 501                // Extract bindable properties for AOT code generation
 167502                var properties = OptionsDiscoveryHelper.ExtractBindableProperties(typeSymbol);
 503
 680504                foreach (var optionsAttr in optionsAttrs)
 505                {
 506                    // Determine validator type and method
 173507                    var validatorTypeSymbol = optionsAttr.ValidatorType;
 173508                    var targetType = validatorTypeSymbol ?? typeSymbol; // Look for method on options class or external 
 173509                    var methodName = optionsAttr.ValidateMethod ?? "Validate"; // Convention: "Validate"
 510
 511                    // Find validation method using convention-based discovery
 173512                    var validatorMethodInfo = OptionsAttributeHelper.FindValidationMethod(targetType, methodName);
 173513                    OptionsValidatorInfo? validatorInfo = validatorMethodInfo.HasValue
 173514                        ? new OptionsValidatorInfo(validatorMethodInfo.Value.MethodName, validatorMethodInfo.Value.IsSta
 173515                        : null;
 516
 517                    // Infer section name if not provided
 173518                    var sectionName = optionsAttr.SectionName
 173519                        ?? Helpers.OptionsNamingHelper.InferSectionName(typeSymbol.Name);
 520
 173521                    var validatorTypeName = validatorTypeSymbol != null
 173522                        ? TypeDiscoveryHelper.GetFullyQualifiedName(validatorTypeSymbol)
 173523                        : null;
 524
 173525                    options.Add(new DiscoveredOptions(
 173526                        typeName,
 173527                        sectionName,
 173528                        optionsAttr.Name,
 173529                        optionsAttr.ValidateOnStart,
 173530                        assembly.Name,
 173531                        sourceFilePath,
 173532                        validatorInfo,
 173533                        optionsAttr.ValidateMethod,
 173534                        validatorTypeName,
 173535                        positionalRecordInfo,
 173536                        properties));
 537                }
 538            }
 539
 540            // Check for [HttpClientOptions] attribute
 1457260541            if (HttpClientOptionsAttributeHelper.HasHttpClientOptionsAttribute(typeSymbol))
 542            {
 0543                var httpAttrInfo = HttpClientOptionsAttributeHelper.GetHttpClientOptionsAttribute(typeSymbol);
 0544                if (httpAttrInfo.HasValue)
 545                {
 546                    // Try to read a literal ClientName property body, if any.
 0547                    var clientNamePropResult = HttpClientOptionsAttributeHelper.TryGetClientNameProperty(typeSymbol, out
 0548                    var propertyNameFromType = clientNamePropResult == ClientNamePropertyResult.Literal ? literalValue :
 549
 0550                    if (HttpClientOptionsAttributeHelper.TryResolveClientName(
 0551                        typeSymbol,
 0552                        httpAttrInfo.Value,
 0553                        propertyNameFromType,
 0554                        out var resolvedClientName))
 555                    {
 0556                        var httpSectionName = HttpClientOptionsAttributeHelper.ResolveSectionName(httpAttrInfo.Value, re
 0557                        var httpTypeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 0558                        var httpSourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 0559                        var capabilities = HttpClientOptionsAttributeHelper.DetectCapabilities(typeSymbol);
 560
 0561                        httpClients.Add(new DiscoveredHttpClient(
 0562                            httpTypeName,
 0563                            resolvedClientName,
 0564                            httpSectionName,
 0565                            assembly.Name,
 0566                            capabilities,
 0567                            httpSourceFilePath));
 568                    }
 569                }
 570            }
 571
 572            // Check for [GenerateFactory] attribute - these types get factories instead of direct registration
 1457260573            if (FactoryDiscoveryHelper.HasGenerateFactoryAttribute(typeSymbol))
 574            {
 25575                var factoryConstructors = FactoryDiscoveryHelper.GetFactoryConstructors(typeSymbol);
 25576                if (factoryConstructors.Count > 0)
 577                {
 578                    // Has at least one constructor with runtime params - generate factory
 24579                    var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 24580                    var interfaces = TypeDiscoveryHelper.GetRegisterableInterfaces(typeSymbol, compilation.Assembly);
 30581                    var interfaceNames = interfaces.Select(i => TypeDiscoveryHelper.GetFullyQualifiedName(i)).ToArray();
 24582                    var generationMode = FactoryDiscoveryHelper.GetFactoryGenerationMode(typeSymbol);
 24583                    var returnTypeOverride = FactoryDiscoveryHelper.GetFactoryReturnInterfaceType(typeSymbol);
 24584                    var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 585
 24586                    factories.Add(new DiscoveredFactory(
 24587                        typeName,
 24588                        interfaceNames,
 24589                        assembly.Name,
 24590                        generationMode,
 24591                        factoryConstructors.ToArray(),
 24592                        returnTypeOverride,
 24593                        sourceFilePath));
 594
 24595                    continue; // Don't add to injectable types - factory handles registration
 596                }
 597                // If no runtime params, fall through to normal registration (with warning in future analyzer)
 598            }
 599
 600            // Check for DecoratorFor<T> attributes
 1457236601            var decoratorInfos = TypeDiscoveryHelper.GetDecoratorForAttributes(typeSymbol);
 2914510602            foreach (var decoratorInfo in decoratorInfos)
 603            {
 19604                var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 19605                decorators.Add(new DiscoveredDecorator(
 19606                    decoratorInfo.DecoratorTypeName,
 19607                    decoratorInfo.ServiceTypeName,
 19608                    decoratorInfo.Order,
 19609                    assembly.Name,
 19610                    sourceFilePath));
 611            }
 612
 613            // Check for OpenDecoratorFor attributes (source-gen only open generic decorators)
 1457236614            var openDecoratorInfos = OpenDecoratorDiscoveryHelper.GetOpenDecoratorForAttributes(typeSymbol);
 2914486615            foreach (var openDecoratorInfo in openDecoratorInfos)
 616            {
 7617                var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 7618                openDecorators.Add(new DiscoveredOpenDecorator(
 7619                    openDecoratorInfo.DecoratorType,
 7620                    openDecoratorInfo.OpenGenericInterface,
 7621                    openDecoratorInfo.Order,
 7622                    assembly.Name,
 7623                    sourceFilePath));
 624            }
 625
 626            // Check for Intercept attributes and collect intercepted services
 1457236627            if (InterceptorDiscoveryHelper.HasInterceptAttributes(typeSymbol))
 628            {
 14629                var lifetime = TypeDiscoveryHelper.DetermineLifetime(typeSymbol);
 14630                if (lifetime.HasValue)
 631                {
 14632                    var classLevelInterceptors = InterceptorDiscoveryHelper.GetInterceptAttributes(typeSymbol);
 14633                    var methodLevelInterceptors = InterceptorDiscoveryHelper.GetMethodLevelInterceptAttributes(typeSymbo
 14634                    var methods = InterceptorDiscoveryHelper.GetInterceptedMethods(typeSymbol, classLevelInterceptors, m
 635
 14636                    if (methods.Count > 0)
 637                    {
 14638                        var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 14639                        var interfaces = TypeDiscoveryHelper.GetRegisterableInterfaces(typeSymbol, compilation.Assembly)
 28640                        var interfaceNames = interfaces.Select(i => TypeDiscoveryHelper.GetFullyQualifiedName(i)).ToArra
 641
 642                        // Collect all unique interceptor types
 14643                        var allInterceptorTypes = classLevelInterceptors
 14644                            .Concat(methodLevelInterceptors)
 17645                            .Select(i => i.InterceptorTypeName)
 14646                            .Distinct()
 14647                            .ToArray();
 648
 14649                        var interceptedSourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 650
 14651                        interceptedServices.Add(new DiscoveredInterceptedService(
 14652                            typeName,
 14653                            interfaceNames,
 14654                            assembly.Name,
 14655                            lifetime.Value,
 14656                            methods.ToArray(),
 14657                            allInterceptorTypes,
 14658                            interceptedSourceFilePath));
 659                    }
 660                }
 661            }
 662
 663            // Check for injectable types (but skip types that are providers, which are handled separately)
 1457236664            if (TypeDiscoveryHelper.IsInjectableType(typeSymbol, isCurrentAssembly) && !ProviderDiscoveryHelper.HasProvi
 665            {
 666                // Determine lifetime first - only include types that are actually injectable
 409762667                var lifetime = TypeDiscoveryHelper.DetermineLifetime(typeSymbol);
 409762668                if (lifetime.HasValue)
 669                {
 233541670                    var interfaces = TypeDiscoveryHelper.GetRegisterableInterfaces(typeSymbol, compilation.Assembly);
 233541671                    var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 233794672                    var interfaceNames = interfaces.Select(i => TypeDiscoveryHelper.GetFullyQualifiedName(i)).ToArray();
 673
 674                    // Capture interface locations for navigation
 233541675                    var interfaceInfos = interfaces.Select(i =>
 233541676                    {
 253677                        var ifaceLocation = i.Locations.FirstOrDefault();
 253678                        var ifaceFilePath = ifaceLocation?.SourceTree?.FilePath;
 253679                        var ifaceLine = ifaceLocation?.GetLineSpan().StartLinePosition.Line + 1 ?? 0;
 253680                        return new InterfaceInfo(TypeDiscoveryHelper.GetFullyQualifiedName(i), ifaceFilePath, ifaceLine)
 233541681                    }).ToArray();
 682
 683                    // Check for [DeferToContainer] attribute - use declared types instead of discovered constructors
 233541684                    var deferredParams = TypeDiscoveryHelper.GetDeferToContainerParameterTypes(typeSymbol);
 685                    TypeDiscoveryHelper.ConstructorParameterInfo[] constructorParams;
 233541686                    if (deferredParams != null)
 687                    {
 688                        // DeferToContainer doesn't support keyed services - convert to simple params
 10689                        constructorParams = deferredParams.Select(t => new TypeDiscoveryHelper.ConstructorParameterInfo(
 690                    }
 691                    else
 692                    {
 233536693                        constructorParams = TypeDiscoveryHelper.GetBestConstructorParametersWithKeys(typeSymbol)?.ToArra
 694                    }
 695
 696                    // Get source file path and line for breadcrumbs (null for external assemblies)
 233541697                    var location = typeSymbol.Locations.FirstOrDefault();
 233541698                    var sourceFilePath = location?.SourceTree?.FilePath;
 233541699                    var sourceLine = location?.GetLineSpan().StartLinePosition.Line + 1 ?? 0; // Convert to 1-based
 700
 701                    // Get [Keyed] attribute keys
 233541702                    var serviceKeys = TypeDiscoveryHelper.GetKeyedServiceKeys(typeSymbol);
 703
 704                    // Check if this type implements IDisposable or IAsyncDisposable
 233541705                    var isDisposable = TypeDiscoveryHelper.IsDisposableType(typeSymbol);
 706
 233541707                    injectableTypes.Add(new DiscoveredType(typeName, interfaceNames, assembly.Name, lifetime.Value, cons
 708                }
 709            }
 710
 711            // Check for hosted service types (BackgroundService or IHostedService implementations)
 1457236712            if (TypeDiscoveryHelper.IsHostedServiceType(typeSymbol, isCurrentAssembly))
 713            {
 7714                var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 7715                var constructorParams = TypeDiscoveryHelper.GetBestConstructorParametersWithKeys(typeSymbol)?.ToArray() 
 7716                var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 717
 7718                hostedServices.Add(new DiscoveredHostedService(
 7719                    typeName,
 7720                    assembly.Name,
 7721                    GeneratorLifetime.Singleton, // Hosted services are always singleton
 7722                    constructorParams,
 7723                    sourceFilePath));
 724            }
 725
 726            // Check for [Provider] attribute
 1457236727            if (ProviderDiscoveryHelper.HasProviderAttribute(typeSymbol))
 728            {
 18729                var discoveredProvider = ProviderDiscoveryHelper.DiscoverProvider(typeSymbol, assembly.Name, generatedNa
 18730                if (discoveredProvider.HasValue)
 731                {
 18732                    providers.Add(discoveredProvider.Value);
 733                }
 734            }
 735
 736            // Check for plugin types (concrete class with parameterless ctor and interfaces)
 1457236737            if (TypeDiscoveryHelper.IsPluginType(typeSymbol, isCurrentAssembly))
 738            {
 405147739                var pluginInterfaces = TypeDiscoveryHelper.GetPluginInterfaces(typeSymbol, compilation.Assembly);
 405147740                if (pluginInterfaces.Count > 0)
 741                {
 1406742                    var typeName = TypeDiscoveryHelper.GetFullyQualifiedName(typeSymbol);
 2817743                    var interfaceNames = pluginInterfaces.Select(i => TypeDiscoveryHelper.GetFullyQualifiedName(i)).ToAr
 1406744                    var attributeNames = TypeDiscoveryHelper.GetPluginAttributes(typeSymbol).ToArray();
 1406745                    var sourceFilePath = typeSymbol.Locations.FirstOrDefault()?.SourceTree?.FilePath;
 1406746                    var order = PluginOrderHelper.GetPluginOrder(typeSymbol);
 747
 1406748                    pluginTypes.Add(new DiscoveredPlugin(typeName, interfaceNames, assembly.Name, attributeNames, source
 749                }
 750            }
 751
 752            // Check for IHubRegistrationPlugin implementations
 753            // NOTE: SignalR hub discovery is now handled by NexusLabs.Needlr.SignalR.Generators
 754
 755            // Check for SemanticKernel plugin types (classes/statics with [KernelFunction] methods)
 756            // NOTE: SemanticKernel plugin discovery is now handled by NexusLabs.Needlr.SemanticKernel.Generators
 757        }
 78632758    }
 759
 760    private static string GenerateTypeRegistrySource(DiscoveryResult discoveryResult, string assemblyName, BreadcrumbWri
 761    {
 457762        var builder = new StringBuilder();
 457763        var safeAssemblyName = GeneratorHelpers.SanitizeIdentifier(assemblyName);
 457764        var hasOptions = discoveryResult.Options.Count > 0;
 457765        var hasHttpClients = discoveryResult.HttpClients.Count > 0;
 457766        var hasConfigBoundRegistrations = hasOptions || hasHttpClients;
 767
 457768        breadcrumbs.WriteFileHeader(builder, assemblyName, "Needlr Type Registry");
 457769        builder.AppendLine("#nullable enable");
 457770        builder.AppendLine();
 457771        builder.AppendLine("using System;");
 457772        builder.AppendLine("using System.Collections.Generic;");
 457773        builder.AppendLine();
 457774        if (hasConfigBoundRegistrations)
 775        {
 146776            builder.AppendLine("using Microsoft.Extensions.Configuration;");
 146777            if (isAotProject || hasHttpClients)
 778            {
 78779                builder.AppendLine("using Microsoft.Extensions.Options;");
 780            }
 781        }
 457782        builder.AppendLine("using Microsoft.Extensions.DependencyInjection;");
 457783        builder.AppendLine();
 457784        builder.AppendLine("using NexusLabs.Needlr;");
 457785        builder.AppendLine("using NexusLabs.Needlr.Generators;");
 457786        builder.AppendLine();
 457787        builder.AppendLine($"namespace {safeAssemblyName}.Generated;");
 457788        builder.AppendLine();
 457789        builder.AppendLine("/// <summary>");
 457790        builder.AppendLine("/// Compile-time generated registry of injectable types and plugins.");
 457791        builder.AppendLine("/// This eliminates the need for runtime reflection-based type discovery.");
 457792        builder.AppendLine("/// </summary>");
 457793        builder.AppendLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"NexusLabs.Needlr.Generators\", \"1
 457794        builder.AppendLine("public static class TypeRegistry");
 457795        builder.AppendLine("{");
 796
 457797        CodeGen.InjectableTypesCodeGenerator.GenerateInjectableTypesArray(builder, discoveryResult.InjectableTypes, brea
 457798        builder.AppendLine();
 457799        CodeGen.PluginsCodeGenerator.GeneratePluginTypesArray(builder, discoveryResult.PluginTypes, breadcrumbs, project
 800
 457801        builder.AppendLine();
 457802        builder.AppendLine("    /// <summary>");
 457803        builder.AppendLine("    /// Gets all injectable types discovered at compile time.");
 457804        builder.AppendLine("    /// </summary>");
 457805        builder.AppendLine("    /// <returns>A read-only list of injectable type information.</returns>");
 457806        builder.AppendLine("    public static IReadOnlyList<InjectableTypeInfo> GetInjectableTypes() => _types;");
 457807        builder.AppendLine();
 457808        builder.AppendLine("    /// <summary>");
 457809        builder.AppendLine("    /// Gets all plugin types discovered at compile time.");
 457810        builder.AppendLine("    /// </summary>");
 457811        builder.AppendLine("    /// <returns>A read-only list of plugin type information.</returns>");
 457812        builder.AppendLine("    public static IReadOnlyList<PluginTypeInfo> GetPluginTypes() => _plugins;");
 813
 457814        if (hasConfigBoundRegistrations)
 815        {
 146816            builder.AppendLine();
 146817            GenerateRegisterOptionsMethod(builder, discoveryResult.Options, discoveryResult.HttpClients, safeAssemblyNam
 818        }
 819
 457820        if (discoveryResult.Providers.Count > 0)
 821        {
 17822            builder.AppendLine();
 17823            CodeGen.DecoratorsCodeGenerator.GenerateRegisterProvidersMethod(builder, discoveryResult.Providers, safeAsse
 824        }
 825
 457826        builder.AppendLine();
 457827        CodeGen.DecoratorsCodeGenerator.GenerateApplyDecoratorsMethod(builder, discoveryResult.Decorators, discoveryResu
 828
 457829        if (discoveryResult.HostedServices.Count > 0)
 830        {
 6831            builder.AppendLine();
 6832            CodeGen.DecoratorsCodeGenerator.GenerateRegisterHostedServicesMethod(builder, discoveryResult.HostedServices
 833        }
 834
 457835        builder.AppendLine("}");
 836
 457837        return builder.ToString();
 838    }
 839
 840    private static void GenerateRegisterOptionsMethod(StringBuilder builder, IReadOnlyList<DiscoveredOptions> options, I
 841    {
 146842        builder.AppendLine("    /// <summary>");
 146843        builder.AppendLine("    /// Registers all discovered options types with the service collection.");
 146844        builder.AppendLine("    /// This binds configuration sections to strongly-typed options classes,");
 146845        builder.AppendLine("    /// and wires up named HttpClient registrations for [HttpClientOptions] types.");
 146846        builder.AppendLine("    /// </summary>");
 146847        builder.AppendLine("    /// <param name=\"services\">The service collection to configure.</param>");
 146848        builder.AppendLine("    /// <param name=\"configuration\">The configuration root to bind options from.</param>")
 146849        builder.AppendLine("    public static void RegisterOptions(IServiceCollection services, IConfiguration configura
 146850        builder.AppendLine("    {");
 851
 146852        if (options.Count == 0 && httpClients.Count == 0)
 853        {
 0854            breadcrumbs.WriteInlineComment(builder, "        ", "No options or HttpClient types discovered");
 855        }
 856        else
 857        {
 146858            if (options.Count > 0)
 859            {
 146860                if (isAotProject)
 861                {
 78862                    CodeGen.OptionsCodeGenerator.GenerateAotOptionsRegistration(builder, options, safeAssemblyName, brea
 863                }
 864                else
 865                {
 68866                    CodeGen.OptionsCodeGenerator.GenerateReflectionOptionsRegistration(builder, options, safeAssemblyNam
 867                }
 868            }
 869
 146870            if (httpClients.Count > 0)
 871            {
 0872                CodeGen.HttpClientCodeGenerator.EmitHttpClientRegistrations(builder, httpClients);
 873            }
 874        }
 875
 146876        builder.AppendLine("    }");
 146877    }
 878
 879}

Methods/Properties

Initialize(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext)
GetBreadcrumbLevel(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider)
GetProjectDirectory(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider)
GetDiagnosticOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider)
ShouldExportGraph(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider)
IsAotProject(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider)
GetAttributeInfoFromCompilation(Microsoft.CodeAnalysis.Compilation)
DiscoverTypes(Microsoft.CodeAnalysis.Compilation,System.String[],System.String[],System.Boolean)
CollectTypesFromAssembly(Microsoft.CodeAnalysis.IAssemblySymbol,System.Collections.Generic.IReadOnlyList`1<System.String>,System.Collections.Generic.IReadOnlyList`1<System.String>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredType>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredPlugin>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredDecorator>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredOpenDecorator>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredInterceptedService>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredFactory>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredOptions>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredHostedService>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredProvider>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.DiscoveredHttpClient>,System.Collections.Generic.List`1<NexusLabs.Needlr.Generators.Models.InaccessibleType>,Microsoft.CodeAnalysis.Compilation,System.Boolean,System.String)
GenerateTypeRegistrySource(NexusLabs.Needlr.Generators.Models.DiscoveryResult,System.String,NexusLabs.Needlr.Generators.BreadcrumbWriter,System.String,System.Boolean)
GenerateRegisterOptionsMethod(System.Text.StringBuilder,System.Collections.Generic.IReadOnlyList`1<NexusLabs.Needlr.Generators.Models.DiscoveredOptions>,System.Collections.Generic.IReadOnlyList`1<NexusLabs.Needlr.Generators.Models.DiscoveredHttpClient>,System.String,NexusLabs.Needlr.Generators.BreadcrumbWriter,System.String,System.Boolean)