|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics;
namespace ILLink.Shared.DataFlow
{
internal sealed class CompilerGeneratedNames
{
private static bool IsGeneratedMemberName(string memberName)
{
return memberName.Length > 0 && memberName[0] == '<';
}
private static bool IsGeneratedMemberName(ReadOnlySpan<byte> memberName)
{
return memberName.Length > 0 && memberName[0] == '<';
}
internal static bool IsLambdaDisplayClass(string className)
{
if (!IsGeneratedMemberName(className))
return false;
// This is true for static lambdas (which are emitted into a class like <>c)
// and for instance lambdas (which are emitted into a class like <>c__DisplayClass1_0)
return className.StartsWith("<>c");
}
internal static bool IsLambdaDisplayClass(ReadOnlySpan<byte> className)
{
if (!IsGeneratedMemberName(className))
return false;
// This is true for static lambdas (which are emitted into a class like <>c)
// and for instance lambdas (which are emitted into a class like <>c__DisplayClass1_0)
return className.StartsWith("<>c"u8);
}
internal static bool IsStateMachineType(string typeName)
{
if (!IsGeneratedMemberName(typeName))
return false;
// State machines are generated into types with names like <OwnerMethodName>d__0
// Or if its nested in a local function the name will look like <<OwnerMethodName>g__Local>d and so on
int i = typeName.LastIndexOf('>');
if (i == -1)
return false;
return typeName.Length > i + 1 && typeName[i + 1] == 'd';
}
internal static bool IsStateMachineType(ReadOnlySpan<byte> typeName)
{
if (!IsGeneratedMemberName(typeName))
return false;
// State machines are generated into types with names like <OwnerMethodName>d__0
// Or if its nested in a local function the name will look like <<OwnerMethodName>g__Local>d and so on
int i = typeName.LastIndexOf('>');
if (i == -1)
return false;
return typeName.Length > i + 1 && typeName[i + 1] == 'd';
}
internal static bool IsStateMachineCurrentField(string fieldName)
{
if (!IsGeneratedMemberName(fieldName))
return false;
int i = fieldName.LastIndexOf('>');
if (i == -1)
return false;
// Current field is <>2__current
return fieldName.Length > i + 1 && fieldName[i + 1] == '2';
}
internal static bool IsStateMachineCurrentField(ReadOnlySpan<byte> fieldName)
{
if (!IsGeneratedMemberName(fieldName))
return false;
int i = fieldName.LastIndexOf('>');
if (i == -1)
return false;
// Current field is <>2__current
return fieldName.Length > i + 1 && fieldName[i + 1] == '2';
}
internal static bool IsStateMachineOrDisplayClass(string name) => IsStateMachineType(name) || IsLambdaDisplayClass(name);
internal static bool IsStateMachineOrDisplayClass(ReadOnlySpan<byte> name) => IsStateMachineType(name) || IsLambdaDisplayClass(name);
internal static bool IsLambdaOrLocalFunction(string methodName) => IsLambdaMethod(methodName) || IsLocalFunction(methodName);
internal static bool IsLambdaOrLocalFunction(ReadOnlySpan<byte> methodName) => IsLambdaMethod(methodName) || IsLocalFunction(methodName);
// Lambda methods have generated names like "<UserMethod>b__0_1" where "UserMethod" is the name
// of the original user code that contains the lambda method declaration.
// The user method name may include a (potentially generic) interface type name for
// explicitly implemented interface methods.
internal static bool IsLambdaMethod(string methodName)
{
if (!IsGeneratedMemberName(methodName))
return false;
int i = methodName.LastIndexOf('>');
if (i == -1)
return false;
// Ignore the method ordinal/generation and lambda ordinal/generation.
return methodName.Length > i + 1 && methodName[i + 1] == 'b';
}
internal static bool IsLambdaMethod(ReadOnlySpan<byte> methodName)
{
if (!IsGeneratedMemberName(methodName))
return false;
int i = methodName.LastIndexOf('>');
if (i == -1)
return false;
// Ignore the method ordinal/generation and lambda ordinal/generation.
return methodName.Length > i + 1 && methodName[i + 1] == 'b';
}
// Local functions have generated names like "<UserMethod>g__LocalFunction|0_1" where "UserMethod" is the name
// of the original user code that contains the lambda method declaration, and "LocalFunction" is the name of
// the local function.
// The user method name may include a (potentially generic) interface type name for
// explicitly implemented interface methods.
internal static bool IsLocalFunction(string methodName)
{
if (!IsGeneratedMemberName(methodName))
return false;
int i = methodName.LastIndexOf('>');
if (i == -1)
return false;
// Ignore the method ordinal/generation and local function ordinal/generation.
return methodName.Length > i + 1 && methodName[i + 1] == 'g';
}
internal static bool IsLocalFunction(ReadOnlySpan<byte> methodName)
{
if (!IsGeneratedMemberName(methodName))
return false;
int i = methodName.LastIndexOf('>');
if (i == -1)
return false;
// Ignore the method ordinal/generation and local function ordinal/generation.
return methodName.Length > i + 1 && methodName[i + 1] == 'g';
}
internal static bool IsExtensionType(string typeName)
{
return typeName.StartsWith("<G>");
}
internal static bool IsExtensionType(ReadOnlySpan<byte> typeName)
{
return typeName.StartsWith("<G>"u8);
}
}
file static class Extensions
{
public static int LastIndexOf(this ReadOnlySpan<byte> span, char ch)
{
// UTF-8 is byte-accurate, so searching for characters that fit under 0x80 means searching for the byte in valid UTF-8 strings.
Debug.Assert(ch < 0x80);
return span.LastIndexOf((byte)ch);
}
}
}
|