File: ConfigurationBindingGenerator.ForSchemaGeneration.cs
Web Access
Project: src\src\Tools\ConfigurationSchemaGenerator\ConfigurationSchemaGenerator.csproj (ConfigurationSchemaGenerator)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using ConfigurationSchemaGenerator;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using SourceGenerators;
using static ConfigurationSchemaGenerator.ConfigSchemaGenerator;
 
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration;
 
/// <summary>
/// Extensions to the ConfigurationBindingGenerator for use in the ConfigurationSchemaGenerator.
/// </summary>
public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context) { }
 
    internal sealed class CompilationData
    {
        public bool LanguageVersionIsSupported { get; } = true;
        public KnownTypeSymbols? TypeSymbols { get; }
 
        public CompilationData(KnownTypeSymbols? typeSymbols)
        {
            TypeSymbols = typeSymbols;
        }
    }
 
    internal sealed partial class Parser
    {
        private readonly ConfigSchemaAttributeInfo _configSchemaInfo;
 
        public Parser(ConfigSchemaAttributeInfo configSchemaInfo, KnownTypeSymbols typeSymbols)
            : this(new CompilationData(typeSymbols))
        {
            _configSchemaInfo = configSchemaInfo;
        }
 
        public SchemaGenerationSpec? GetSchemaGenerationSpec(CancellationToken cancellationToken)
        {
            var types = new List<TypeSpec>();
            if (_configSchemaInfo.Types is not null)
            {
                foreach (var type in _configSchemaInfo.Types)
                {
                    var typeParseInfo = TypeParseInfo.Create(type, MethodsToGen.None, invocation: null);
 
                    _typesToParse.Enqueue(typeParseInfo);
                    types.Add(CreateTopTypeSpec(cancellationToken));
                }
            }
 
            return new SchemaGenerationSpec
            {
                ConfigurationTypes = types,
                ConfigurationPaths = _configSchemaInfo.ConfigurationPaths,
                ExclusionPaths = _configSchemaInfo.ExclusionPaths,
                LogCategories = _configSchemaInfo.LogCategories,
                AllTypes = _createdTypeSpecs.Values.ToImmutableEquatableArray()
            };
        }
 
        private TypeSpec CreateTopTypeSpec(CancellationToken cancellationToken)
        {
            Debug.Assert(_typesToParse.Count == 1, "there should only be one type to parse to start.");
            TypeSpec result = null;
 
            while (_typesToParse.Count > 0)
            {
                cancellationToken.ThrowIfCancellationRequested();
 
                TypeParseInfo typeParseInfo = _typesToParse.Dequeue();
                ITypeSymbol typeSymbol = typeParseInfo.TypeSymbol;
 
                TypeSpec currentResult;
                if (!_createdTypeSpecs.TryGetValue(typeSymbol, out currentResult))
                {
                    currentResult = CreateTypeSpec(typeParseInfo);
                    _createdTypeSpecs.Add(typeSymbol, currentResult);
                }
 
                result ??= currentResult;
            }
 
            Debug.Assert(result is not null);
            return result;
        }
    }
}