mirror of https://github.com/icsharpcode/ILSpy.git
7 changed files with 229 additions and 2 deletions
@ -0,0 +1,76 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace LocalFunctions |
||||||
|
{ |
||||||
|
class LocalFunctions |
||||||
|
{ |
||||||
|
int field; |
||||||
|
|
||||||
|
public static void Main(string[] args) |
||||||
|
{ |
||||||
|
StaticContextNoCapture(10); |
||||||
|
StaticContextSimpleCapture(10); |
||||||
|
StaticContextCaptureInForLoop(10); |
||||||
|
var inst = new LocalFunctions() { field = 10 }; |
||||||
|
inst.ContextNoCapture(); |
||||||
|
inst.ContextSimpleCapture(); |
||||||
|
inst.ContextCaptureInForLoop(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void StaticContextNoCapture(int length) |
||||||
|
{ |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
LocalWrite("Hello " + i); |
||||||
|
} |
||||||
|
|
||||||
|
void LocalWrite(string s) => Console.WriteLine(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static void StaticContextSimpleCapture(int length) |
||||||
|
{ |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
LocalWrite(); |
||||||
|
} |
||||||
|
|
||||||
|
void LocalWrite() => Console.WriteLine("Hello " + length); |
||||||
|
} |
||||||
|
|
||||||
|
public static void StaticContextCaptureInForLoop(int length) |
||||||
|
{ |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
void LocalWrite() => Console.WriteLine("Hello " + i + "/" + length); |
||||||
|
LocalWrite(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void ContextNoCapture() |
||||||
|
{ |
||||||
|
for (int i = 0; i < field; i++) { |
||||||
|
LocalWrite("Hello " + i); |
||||||
|
} |
||||||
|
|
||||||
|
void LocalWrite(string s) => Console.WriteLine(s); |
||||||
|
} |
||||||
|
|
||||||
|
public void ContextSimpleCapture() |
||||||
|
{ |
||||||
|
for (int i = 0; i < field; i++) { |
||||||
|
LocalWrite(); |
||||||
|
} |
||||||
|
|
||||||
|
void LocalWrite() => Console.WriteLine("Hello " + field); |
||||||
|
} |
||||||
|
|
||||||
|
public void ContextCaptureInForLoop() |
||||||
|
{ |
||||||
|
for (int i = 0; i < field; i++) { |
||||||
|
void LocalWrite() => Console.WriteLine("Hello " + i + "/" + field); |
||||||
|
LocalWrite(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
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); |
||||||
|
|
||||||
|
if ((method.Attributes & MethodAttributes.Assembly) == 0 || !method.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; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Newer Roslyn versions use the format "<callerName>g__functionName|x_y"
|
||||||
|
/// Older versions use "<callerName>g__functionNamex_y"
|
||||||
|
/// </summary>
|
||||||
|
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<bool, Unit> |
||||||
|
{ |
||||||
|
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<bool> signature) => false; |
||||||
|
public bool GetGenericInstantiation(bool genericType, ImmutableArray<bool> 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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue