using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Text.RegularExpressions;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
class LocalFunctionDecompiler : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
throw new NotImplementedException();
}
public static bool IsLocalFunctionMethod(PEFile module, MethodDefinitionHandle methodHandle)
{
var metadata = module.Metadata;
var method = metadata.GetMethodDefinition(methodHandle);
var declaringType = method.GetDeclaringType();
if ((method.Attributes & MethodAttributes.Assembly) == 0 || !(method.IsCompilerGenerated(metadata) || declaringType.IsCompilerGenerated(metadata)))
return false;
if (!ParseLocalFunctionName(metadata.GetString(method.Name), out _, out _))
return false;
return true;
}
public static bool IsLocalFunctionDisplayClass(PEFile module, TypeDefinitionHandle typeHandle)
{
var metadata = module.Metadata;
var type = metadata.GetTypeDefinition(typeHandle);
if ((type.Attributes & TypeAttributes.NestedPrivate) == 0)
return false;
if (!type.HasGeneratedName(metadata))
return false;
var declaringTypeHandle = type.GetDeclaringType();
var declaringType = metadata.GetTypeDefinition(declaringTypeHandle);
foreach (var method in declaringType.GetMethods()) {
if (!IsLocalFunctionMethod(module, method))
continue;
var md = metadata.GetMethodDefinition(method);
if (md.DecodeSignature(new FindTypeDecoder(typeHandle), default).ParameterTypes.Any())
return true;
}
return false;
}
///
/// Newer Roslyn versions use the format "<callerName>g__functionName|x_y"
/// Older versions use "<callerName>g__functionNamex_y"
///
static readonly Regex functionNameRegex = new Regex(@"^<(.*)>g__(.*)\|{0,1}\d+(_\d+)?$", RegexOptions.Compiled);
static bool ParseLocalFunctionName(string name, out string callerName, out string functionName)
{
callerName = null;
functionName = null;
if (string.IsNullOrWhiteSpace(name))
return false;
var match = functionNameRegex.Match(name);
callerName = match.Groups[1].Value;
functionName = match.Groups[2].Value;
return match.Success;
}
struct FindTypeDecoder : ISignatureTypeProvider
{
TypeDefinitionHandle handle;
public FindTypeDecoder(TypeDefinitionHandle handle)
{
this.handle = handle;
}
public bool GetArrayType(bool elementType, ArrayShape shape) => elementType;
public bool GetByReferenceType(bool elementType) => elementType;
public bool GetFunctionPointerType(MethodSignature signature) => false;
public bool GetGenericInstantiation(bool genericType, ImmutableArray typeArguments) => genericType;
public bool GetGenericMethodParameter(Unit genericContext, int index) => false;
public bool GetGenericTypeParameter(Unit genericContext, int index) => false;
public bool GetModifiedType(bool modifier, bool unmodifiedType, bool isRequired) => unmodifiedType;
public bool GetPinnedType(bool elementType) => elementType;
public bool GetPointerType(bool elementType) => elementType;
public bool GetPrimitiveType(PrimitiveTypeCode typeCode) => false;
public bool GetSZArrayType(bool elementType) => false;
public bool GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
return this.handle == handle;
}
public bool GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
return false;
}
public bool GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
}
}
}