File: Helpers\KnownTypeSymbols.cs
Web Access
Project: src\src\libraries\System.Text.Json\gen\System.Text.Json.SourceGeneration.Roslyn4.0.csproj (System.Text.Json.SourceGeneration)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
 
namespace System.Text.Json.SourceGeneration
{
    internal sealed class KnownTypeSymbols
    {
        public KnownTypeSymbols(Compilation compilation)
            => Compilation = compilation;
 
        public Compilation Compilation { get; }
 
        // Caches a set of types with built-in converter support. Populated by the Parser class.
        public HashSet<ITypeSymbol>? BuiltInSupportTypes { get; set; }
 
        public INamedTypeSymbol? IListOfTType => GetOrResolveType(typeof(IList<>), ref _IListOfTType);
        private Option<INamedTypeSymbol?> _IListOfTType;
 
        public INamedTypeSymbol? ICollectionOfTType => GetOrResolveType(typeof(ICollection<>), ref _ICollectionOfTType);
        private Option<INamedTypeSymbol?> _ICollectionOfTType;
 
        public INamedTypeSymbol? IEnumerableType => GetOrResolveType(typeof(IEnumerable), ref _IEnumerableType);
        private Option<INamedTypeSymbol?> _IEnumerableType;
 
        public INamedTypeSymbol? IEnumerableOfTType => GetOrResolveType(typeof(IEnumerable<>), ref _IEnumerableOfTType);
        private Option<INamedTypeSymbol?> _IEnumerableOfTType;
 
        public INamedTypeSymbol? ListOfTType => GetOrResolveType(typeof(List<>), ref _ListOfTType);
        private Option<INamedTypeSymbol?> _ListOfTType;
 
        public INamedTypeSymbol? DictionaryOfTKeyTValueType => GetOrResolveType(typeof(Dictionary<,>), ref _DictionaryOfTKeyTValueType);
        private Option<INamedTypeSymbol?> _DictionaryOfTKeyTValueType;
 
        public INamedTypeSymbol? IAsyncEnumerableOfTType => GetOrResolveType("System.Collections.Generic.IAsyncEnumerable`1", ref _AsyncEnumerableOfTType);
        private Option<INamedTypeSymbol?> _AsyncEnumerableOfTType;
 
        public INamedTypeSymbol? IDictionaryOfTKeyTValueType => GetOrResolveType(typeof(IDictionary<,>), ref _IDictionaryOfTKeyTValueType);
        private Option<INamedTypeSymbol?> _IDictionaryOfTKeyTValueType;
 
        public INamedTypeSymbol? IReadonlyDictionaryOfTKeyTValueType => GetOrResolveType(typeof(IReadOnlyDictionary<,>), ref _IReadonlyDictionaryOfTKeyTValueType);
        private Option<INamedTypeSymbol?> _IReadonlyDictionaryOfTKeyTValueType;
 
        public INamedTypeSymbol? ISetOfTType => GetOrResolveType(typeof(ISet<>), ref _ISetOfTType);
        private Option<INamedTypeSymbol?> _ISetOfTType;
 
        public INamedTypeSymbol? StackOfTType => GetOrResolveType(typeof(Stack<>), ref _StackOfTType);
        private Option<INamedTypeSymbol?> _StackOfTType;
 
        public INamedTypeSymbol? QueueOfTType => GetOrResolveType(typeof(Queue<>), ref _QueueOfTType);
        private Option<INamedTypeSymbol?> _QueueOfTType;
 
        public INamedTypeSymbol? ConcurrentStackType => GetOrResolveType(typeof(ConcurrentStack<>), ref _ConcurrentStackType);
        private Option<INamedTypeSymbol?> _ConcurrentStackType;
 
        public INamedTypeSymbol? ConcurrentQueueType => GetOrResolveType(typeof(ConcurrentQueue<>), ref _ConcurrentQueueType);
        private Option<INamedTypeSymbol?> _ConcurrentQueueType;
 
        public INamedTypeSymbol? IDictionaryType => GetOrResolveType(typeof(IDictionary), ref _IDictionaryType);
        private Option<INamedTypeSymbol?> _IDictionaryType;
 
        public INamedTypeSymbol? IListType => GetOrResolveType(typeof(IList), ref _IListType);
        private Option<INamedTypeSymbol?> _IListType;
 
        public INamedTypeSymbol? StackType => GetOrResolveType(typeof(Stack), ref _StackType);
        private Option<INamedTypeSymbol?> _StackType;
 
        public INamedTypeSymbol? QueueType => GetOrResolveType(typeof(Queue), ref _QueueType);
        private Option<INamedTypeSymbol?> _QueueType;
 
        public INamedTypeSymbol? KeyValuePair => GetOrResolveType(typeof(KeyValuePair<,>), ref _KeyValuePair);
        private Option<INamedTypeSymbol?> _KeyValuePair;
 
        public INamedTypeSymbol? ImmutableArrayType => GetOrResolveType(typeof(ImmutableArray<>), ref _ImmutableArrayType);
        private Option<INamedTypeSymbol?> _ImmutableArrayType;
 
        public INamedTypeSymbol? ImmutableListType => GetOrResolveType(typeof(ImmutableList<>), ref _ImmutableListType);
        private Option<INamedTypeSymbol?> _ImmutableListType;
 
        public INamedTypeSymbol? IImmutableListType => GetOrResolveType(typeof(IImmutableList<>), ref _IImmutableListType);
        private Option<INamedTypeSymbol?> _IImmutableListType;
 
        public INamedTypeSymbol? ImmutableStackType => GetOrResolveType(typeof(ImmutableStack<>), ref _ImmutableStackType);
        private Option<INamedTypeSymbol?> _ImmutableStackType;
 
        public INamedTypeSymbol? IImmutableStackType => GetOrResolveType(typeof(IImmutableStack<>), ref _IImmutableStackType);
        private Option<INamedTypeSymbol?> _IImmutableStackType;
 
        public INamedTypeSymbol? ImmutableQueueType => GetOrResolveType(typeof(ImmutableQueue<>), ref _ImmutableQueueType);
        private Option<INamedTypeSymbol?> _ImmutableQueueType;
 
        public INamedTypeSymbol? IImmutableQueueType => GetOrResolveType(typeof(IImmutableQueue<>), ref _IImmutableQueueType);
        private Option<INamedTypeSymbol?> _IImmutableQueueType;
 
        public INamedTypeSymbol? ImmutableSortedType => GetOrResolveType(typeof(ImmutableSortedSet<>), ref _ImmutableSortedType);
        private Option<INamedTypeSymbol?> _ImmutableSortedType;
 
        public INamedTypeSymbol? ImmutableHashSetType => GetOrResolveType(typeof(ImmutableHashSet<>), ref _ImmutableHashSetType);
        private Option<INamedTypeSymbol?> _ImmutableHashSetType;
 
        public INamedTypeSymbol? IImmutableSetType => GetOrResolveType(typeof(IImmutableSet<>), ref _IImmutableSetType);
        private Option<INamedTypeSymbol?> _IImmutableSetType;
 
        public INamedTypeSymbol? ImmutableDictionaryType => GetOrResolveType(typeof(ImmutableDictionary<,>), ref _ImmutableDictionaryType);
        private Option<INamedTypeSymbol?> _ImmutableDictionaryType;
 
        public INamedTypeSymbol? ImmutableSortedDictionaryType => GetOrResolveType(typeof(ImmutableSortedDictionary<,>), ref _ImmutableSortedDictionaryType);
        private Option<INamedTypeSymbol?> _ImmutableSortedDictionaryType;
 
        public INamedTypeSymbol? IImmutableDictionaryType => GetOrResolveType(typeof(IImmutableDictionary<,>), ref _IImmutableDictionaryType);
        private Option<INamedTypeSymbol?> _IImmutableDictionaryType;
 
        public INamedTypeSymbol? KeyedCollectionType => GetOrResolveType(typeof(KeyedCollection<,>), ref _KeyedCollectionType);
        private Option<INamedTypeSymbol?> _KeyedCollectionType;
 
        public INamedTypeSymbol ObjectType => _ObjectType ??= Compilation.GetSpecialType(SpecialType.System_Object);
        private INamedTypeSymbol? _ObjectType;
 
        public INamedTypeSymbol StringType => _StringType ??= Compilation.GetSpecialType(SpecialType.System_String);
        private INamedTypeSymbol? _StringType;
 
        public INamedTypeSymbol? DateTimeOffsetType => GetOrResolveType(typeof(DateTimeOffset), ref _DateTimeOffsetType);
        private Option<INamedTypeSymbol?> _DateTimeOffsetType;
 
        public INamedTypeSymbol? TimeSpanType => GetOrResolveType(typeof(TimeSpan), ref _TimeSpanType);
        private Option<INamedTypeSymbol?> _TimeSpanType;
 
        public INamedTypeSymbol? DateOnlyType => GetOrResolveType("System.DateOnly", ref _DateOnlyType);
        private Option<INamedTypeSymbol?> _DateOnlyType;
 
        public INamedTypeSymbol? TimeOnlyType => GetOrResolveType("System.TimeOnly", ref _TimeOnlyType);
        private Option<INamedTypeSymbol?> _TimeOnlyType;
 
        public INamedTypeSymbol? Int128Type => GetOrResolveType("System.Int128", ref _Int128Type);
        private Option<INamedTypeSymbol?> _Int128Type;
 
        public INamedTypeSymbol? UInt128Type => GetOrResolveType("System.UInt128", ref _UInt128Type);
        private Option<INamedTypeSymbol?> _UInt128Type;
 
        public INamedTypeSymbol? HalfType => GetOrResolveType("System.Half", ref _HalfType);
        private Option<INamedTypeSymbol?> _HalfType;
 
        public IArrayTypeSymbol? ByteArrayType => _ByteArrayType.HasValue
            ? _ByteArrayType.Value
            : (_ByteArrayType = new(Compilation.CreateArrayTypeSymbol(Compilation.GetSpecialType(SpecialType.System_Byte), rank: 1))).Value;
 
        private Option<IArrayTypeSymbol?> _ByteArrayType;
 
        public INamedTypeSymbol? MemoryByteType => _MemoryByteType.HasValue
            ? _MemoryByteType.Value
            : (_MemoryByteType = new(MemoryType?.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)))).Value;
 
        private Option<INamedTypeSymbol?> _MemoryByteType;
 
        public INamedTypeSymbol? ReadOnlyMemoryByteType => _ReadOnlyMemoryByteType.HasValue
            ? _ReadOnlyMemoryByteType.Value
            : (_ReadOnlyMemoryByteType = new(ReadOnlyMemoryType?.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)))).Value;
 
        private Option<INamedTypeSymbol?> _ReadOnlyMemoryByteType;
 
        public INamedTypeSymbol? GuidType => GetOrResolveType(typeof(Guid), ref _GuidType);
        private Option<INamedTypeSymbol?> _GuidType;
 
        public INamedTypeSymbol? UriType => GetOrResolveType(typeof(Uri), ref _UriType);
        private Option<INamedTypeSymbol?> _UriType;
 
        public INamedTypeSymbol? VersionType => GetOrResolveType(typeof(Version), ref _VersionType);
        private Option<INamedTypeSymbol?> _VersionType;
 
        // System.Text.Json types
        public INamedTypeSymbol? JsonConverterType => GetOrResolveType("System.Text.Json.Serialization.JsonConverter", ref _JsonConverterType);
        private Option<INamedTypeSymbol?> _JsonConverterType;
 
        public INamedTypeSymbol? JsonSerializerContextType => GetOrResolveType("System.Text.Json.Serialization.JsonSerializerContext", ref _JsonSerializerContextType);
        private Option<INamedTypeSymbol?> _JsonSerializerContextType;
 
        public INamedTypeSymbol? JsonSerializableAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonSerializableAttribute", ref _JsonSerializableAttributeType);
        private Option<INamedTypeSymbol?> _JsonSerializableAttributeType;
 
        public INamedTypeSymbol? JsonDocumentType => GetOrResolveType("System.Text.Json.JsonDocument", ref _JsonDocumentType);
        private Option<INamedTypeSymbol?> _JsonDocumentType;
 
        public INamedTypeSymbol? JsonElementType => GetOrResolveType("System.Text.Json.JsonElement", ref _JsonElementType);
        private Option<INamedTypeSymbol?> _JsonElementType;
 
        public INamedTypeSymbol? JsonNodeType => GetOrResolveType("System.Text.Json.Nodes.JsonNode", ref _JsonNodeType);
        private Option<INamedTypeSymbol?> _JsonNodeType;
 
        public INamedTypeSymbol? JsonValueType => GetOrResolveType("System.Text.Json.Nodes.JsonValue", ref _JsonValueType);
        private Option<INamedTypeSymbol?> _JsonValueType;
 
        public INamedTypeSymbol? JsonObjectType => GetOrResolveType("System.Text.Json.Nodes.JsonObject", ref _JsonObjectType);
        private Option<INamedTypeSymbol?> _JsonObjectType;
 
        public INamedTypeSymbol? JsonArrayType => GetOrResolveType("System.Text.Json.Nodes.JsonArray", ref _JsonArrayType);
        private Option<INamedTypeSymbol?> _JsonArrayType;
 
        // System.Text.Json attributes
        public INamedTypeSymbol? JsonConverterAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonConverterAttribute", ref _JsonConverterAttributeType);
        private Option<INamedTypeSymbol?> _JsonConverterAttributeType;
 
        public INamedTypeSymbol? JsonDerivedTypeAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonDerivedTypeAttribute", ref _JsonDerivedTypeAttributeType);
        private Option<INamedTypeSymbol?> _JsonDerivedTypeAttributeType;
 
        public INamedTypeSymbol? JsonNumberHandlingAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonNumberHandlingAttribute", ref _JsonNumberHandlingAttributeType);
        private Option<INamedTypeSymbol?> _JsonNumberHandlingAttributeType;
 
        public INamedTypeSymbol? JsonObjectCreationHandlingAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonObjectCreationHandlingAttribute", ref _JsonObjectCreationHandlingAttributeType);
        private Option<INamedTypeSymbol?> _JsonObjectCreationHandlingAttributeType;
 
        public INamedTypeSymbol? JsonSourceGenerationOptionsAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute", ref _JsonSourceGenerationOptionsAttributeType);
        private Option<INamedTypeSymbol?> _JsonSourceGenerationOptionsAttributeType;
 
        public INamedTypeSymbol? JsonUnmappedMemberHandlingAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonUnmappedMemberHandlingAttribute", ref _JsonUnmappedMemberHandlingAttributeType);
        private Option<INamedTypeSymbol?> _JsonUnmappedMemberHandlingAttributeType;
 
        public INamedTypeSymbol? JsonConstructorAttributeType => GetOrResolveType("System.Text.Json.Serialization.JsonConstructorAttribute", ref _JsonConstructorAttributeType);
        private Option<INamedTypeSymbol?> _JsonConstructorAttributeType;
 
        public INamedTypeSymbol? SetsRequiredMembersAttributeType => GetOrResolveType("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", ref _SetsRequiredMembersAttributeType);
        private Option<INamedTypeSymbol?> _SetsRequiredMembersAttributeType;
 
        public INamedTypeSymbol? JsonStringEnumConverterType => GetOrResolveType("System.Text.Json.Serialization.JsonStringEnumConverter", ref _JsonStringEnumConverterType);
        private Option<INamedTypeSymbol?> _JsonStringEnumConverterType;
 
        public INamedTypeSymbol? JsonStringEnumConverterOfTType => GetOrResolveType("System.Text.Json.Serialization.JsonStringEnumConverter`1", ref _JsonStringEnumConverterOfTType);
        private Option<INamedTypeSymbol?> _JsonStringEnumConverterOfTType;
 
        public INamedTypeSymbol? IJsonOnSerializingType => GetOrResolveType(JsonConstants.IJsonOnSerializingFullName, ref _IJsonOnSerializingType);
        private Option<INamedTypeSymbol?> _IJsonOnSerializingType;
 
        public INamedTypeSymbol? IJsonOnSerializedType => GetOrResolveType(JsonConstants.IJsonOnSerializedFullName, ref _IJsonOnSerializedType);
        private Option<INamedTypeSymbol?> _IJsonOnSerializedType;
 
        // Unsupported types
        public INamedTypeSymbol? DelegateType => _DelegateType ??= Compilation.GetSpecialType(SpecialType.System_Delegate);
        private INamedTypeSymbol? _DelegateType;
 
        public INamedTypeSymbol? MemberInfoType => GetOrResolveType(typeof(MemberInfo), ref _MemberInfoType);
        private Option<INamedTypeSymbol?> _MemberInfoType;
 
        public INamedTypeSymbol? SerializationInfoType => GetOrResolveType(typeof(Runtime.Serialization.SerializationInfo), ref _SerializationInfoType);
        private Option<INamedTypeSymbol?> _SerializationInfoType;
 
        public INamedTypeSymbol? IntPtrType => GetOrResolveType(typeof(IntPtr), ref _IntPtrType);
        private Option<INamedTypeSymbol?> _IntPtrType;
 
        public INamedTypeSymbol? UIntPtrType => GetOrResolveType(typeof(UIntPtr), ref _UIntPtrType);
        private Option<INamedTypeSymbol?> _UIntPtrType;
 
        public INamedTypeSymbol? MemoryType => GetOrResolveType(typeof(Memory<>), ref _MemoryType);
        private Option<INamedTypeSymbol?> _MemoryType;
 
        public INamedTypeSymbol? ReadOnlyMemoryType => GetOrResolveType(typeof(ReadOnlyMemory<>), ref _ReadOnlyMemoryType);
        private Option<INamedTypeSymbol?> _ReadOnlyMemoryType;
 
        public bool IsImmutableEnumerableType(ITypeSymbol type, out string? factoryTypeFullName)
        {
            if (type is not INamedTypeSymbol { IsGenericType: true, ConstructedFrom: INamedTypeSymbol genericTypeDef })
            {
                factoryTypeFullName = null;
                return false;
            }
 
            SymbolEqualityComparer cmp = SymbolEqualityComparer.Default;
            if (cmp.Equals(genericTypeDef, ImmutableArrayType))
            {
                factoryTypeFullName = typeof(ImmutableArray).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableListType) ||
                cmp.Equals(genericTypeDef, IImmutableListType))
            {
                factoryTypeFullName = typeof(ImmutableList).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableStackType) ||
                cmp.Equals(genericTypeDef, IImmutableStackType))
            {
                factoryTypeFullName = typeof(ImmutableStack).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableQueueType) ||
                cmp.Equals(genericTypeDef, IImmutableQueueType))
            {
                factoryTypeFullName = typeof(ImmutableQueue).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableHashSetType) ||
                cmp.Equals(genericTypeDef, IImmutableSetType))
            {
                factoryTypeFullName = typeof(ImmutableHashSet).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableSortedType))
            {
                factoryTypeFullName = typeof(ImmutableSortedSet).FullName;
                return true;
            }
 
            factoryTypeFullName = null;
            return false;
        }
 
        public bool IsImmutableDictionaryType(ITypeSymbol type, out string? factoryTypeFullName)
        {
            if (type is not INamedTypeSymbol { IsGenericType: true, ConstructedFrom: INamedTypeSymbol genericTypeDef })
            {
                factoryTypeFullName = null;
                return false;
            }
 
            SymbolEqualityComparer cmp = SymbolEqualityComparer.Default;
 
            if (cmp.Equals(genericTypeDef, ImmutableDictionaryType) ||
                cmp.Equals(genericTypeDef, IImmutableDictionaryType))
            {
                factoryTypeFullName = typeof(ImmutableDictionary).FullName;
                return true;
            }
 
            if (cmp.Equals(genericTypeDef, ImmutableSortedDictionaryType))
            {
                factoryTypeFullName = typeof(ImmutableSortedDictionary).FullName;
                return true;
            }
 
            factoryTypeFullName = null;
            return false;
        }
 
        private INamedTypeSymbol? GetOrResolveType(Type type, ref Option<INamedTypeSymbol?> field)
            => GetOrResolveType(type.FullName!, ref field);
 
        private INamedTypeSymbol? GetOrResolveType(string fullyQualifiedName, ref Option<INamedTypeSymbol?> field)
        {
            if (field.HasValue)
            {
                return field.Value;
            }
 
            INamedTypeSymbol? type = Compilation.GetBestTypeByMetadataName(fullyQualifiedName);
            field = new(type);
            return type;
        }
 
        private readonly struct Option<T>
        {
            public readonly bool HasValue;
            public readonly T Value;
 
            public Option(T value)
            {
                HasValue = true;
                Value = value;
            }
        }
    }
}