File: Parsing\TypeSymbolExtensions.cs
Web Access
Project: src\src\Generators\Microsoft.Gen.Logging\Microsoft.Gen.Logging.csproj (Microsoft.Gen.Logging)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.Gen.Shared;
 
namespace Microsoft.Gen.Logging.Parsing;
 
internal static class TypeSymbolExtensions
{
    internal static bool IsEnumerable(this ITypeSymbol sym, SymbolHolder symbols)
        => (sym.ImplementsInterface(symbols.EnumerableSymbol) || SymbolEqualityComparer.Default.Equals(sym, symbols.EnumerableSymbol))
            && sym.SpecialType != SpecialType.System_String;
 
    internal static bool ImplementsIConvertible(this ITypeSymbol sym, SymbolHolder symbols)
    {
        sym = sym.GetPossiblyNullWrappedType();
 
        foreach (var member in sym.GetMembers("ToString"))
        {
            if (member is IMethodSymbol ts)
            {
                if (ts.DeclaredAccessibility == Accessibility.Public)
                {
                    if (ts.Arity == 0
                        && ts.Parameters.Length == 1
                        && SymbolEqualityComparer.Default.Equals(ts.Parameters[0].Type, symbols.FormatProviderSymbol))
                    {
                        return true;
                    }
                }
            }
        }
 
        return false;
    }
 
    internal static bool ImplementsIFormattable(this ITypeSymbol sym, SymbolHolder symbols)
    {
        sym = sym.GetPossiblyNullWrappedType();
 
        foreach (var member in sym.GetMembers("ToString"))
        {
            if (member is IMethodSymbol ts)
            {
                if (ts.DeclaredAccessibility == Accessibility.Public)
                {
                    if (ts.Arity == 0
                        && ts.Parameters.Length == 2
                        && ts.Parameters[0].Type.SpecialType == SpecialType.System_String
                        && SymbolEqualityComparer.Default.Equals(ts.Parameters[1].Type, symbols.FormatProviderSymbol))
                    {
                        return true;
                    }
                }
            }
        }
 
        return false;
    }
 
    internal static bool ImplementsISpanFormattable(this ITypeSymbol sym, SymbolHolder symbols)
    {
        sym = sym.GetPossiblyNullWrappedType();
 
        return symbols.SpanFormattableSymbol != null && (sym.ImplementsInterface(symbols.SpanFormattableSymbol) || SymbolEqualityComparer.Default.Equals(sym, symbols.SpanFormattableSymbol));
    }
 
    internal static bool IsSpecialType(this ITypeSymbol typeSymbol, SymbolHolder symbols)
        => typeSymbol.SpecialType != SpecialType.None ||
        typeSymbol.OriginalDefinition.SpecialType != SpecialType.None ||
#pragma warning disable RS1024
        symbols.IgnorePropertiesSymbols.Contains(typeSymbol);
#pragma warning restore RS1024
 
    internal static bool HasCustomToString(this ITypeSymbol type)
    {
        ITypeSymbol? current = type;
        while (current != null && current.SpecialType != SpecialType.System_Object)
        {
            if (current.GetMembers("ToString").Where(m => m.Kind == SymbolKind.Method && m.DeclaredAccessibility == Accessibility.Public).Cast<IMethodSymbol>().Any(m => m.Parameters.Length == 0))
            {
                return true;
            }
 
            current = current.BaseType;
        }
 
        return false;
    }
 
    internal static ITypeSymbol GetPossiblyNullWrappedType(this ITypeSymbol sym)
    {
        if (sym is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType && namedTypeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
        {
            return namedTypeSymbol.TypeArguments[0];
        }
 
        return sym;
    }
}