File: src\Shared\RoslynUtils\TypeHelper.cs
Web Access
Project: src\src\Http\Routing\src\Microsoft.AspNetCore.Routing.csproj (Microsoft.AspNetCore.Routing)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
 
namespace System.Runtime.CompilerServices;
 
internal static class TypeHelper
{
    /// <summary>
    /// Checks to see if a given type is compiler generated.
    /// <remarks>
    /// The compiler will annotate either the target type or the declaring type
    /// with the CompilerGenerated attribute. We walk up the declaring types until
    /// we find a CompilerGenerated attribute or declare the type as not compiler
    /// generated otherwise.
    /// </remarks>
    /// </summary>
    /// <param name="type">The type to evaluate.</param>
    /// <returns><see langword="true" /> if <paramref name="type"/> is compiler generated.</returns>
    internal static bool IsCompilerGeneratedType(Type? type = null)
    {
        if (type is not null)
        {
            return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute)) || IsCompilerGeneratedType(type.DeclaringType);
        }
        return false;
    }
 
    /// <summary>
    /// Checks to see if a given method is compiler generated.
    /// </summary>
    /// <param name="method">The method to evaluate.</param>
    /// <returns><see langword="true" /> if <paramref name="method"/> is compiler generated.</returns>
    private static bool IsCompilerGeneratedMethod(MethodInfo method)
    {
        return Attribute.IsDefined(method, typeof(CompilerGeneratedAttribute)) || IsCompilerGeneratedType(method.DeclaringType);
    }
 
    /// <summary>
    /// Parses generated local function name out of a generated method name. This code is a stop-gap and exists to address the issues with extracting
    /// original method names from generated local functions. See https://github.com/dotnet/roslyn/issues/55651 for more info.
    /// </summary>
    private static bool TryParseLocalFunctionName(string generatedName, [NotNullWhen(true)] out string? originalName)
    {
        originalName = null;
 
        var startIndex = generatedName.LastIndexOf(">g__", StringComparison.Ordinal);
        var endIndex = generatedName.LastIndexOf("|", StringComparison.Ordinal);
        if (startIndex >= 0 && endIndex >= 0 && endIndex - startIndex > 4)
        {
            originalName = generatedName.Substring(startIndex + 4, endIndex - startIndex - 4);
            return true;
        }
 
        return false;
    }
 
    /// <summary>
    /// Tries to get non-compiler-generated name of function. This parses generated local function names out of a generated method name if possible.
    /// </summary>
    internal static bool TryGetNonCompilerGeneratedMethodName(MethodInfo method, [NotNullWhen(true)] out string? originalName)
    {
        var methodName = method.Name;
 
        if (!IsCompilerGeneratedMethod(method))
        {
            originalName = methodName;
            return true;
        }
 
        return TryParseLocalFunctionName(methodName, out originalName);
    }
}