Browse Source

Fix #2196: Add support for extern local functions.

pull/2201/head
Siegfried Pammer 5 years ago
parent
commit
d3b0e4cd72
  1. 13
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  2. 36
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 19
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  4. 35
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

13
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -18,6 +18,9 @@ @@ -18,6 +18,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if CS90
using System.Runtime.InteropServices;
#endif
namespace LocalFunctions
{
@ -836,5 +839,15 @@ namespace LocalFunctions @@ -836,5 +839,15 @@ namespace LocalFunctions
}
}
}
#if CS90
public void Issue2196()
{
EnumWindows(IntPtr.Zero, IntPtr.Zero);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "EnumWindows")]
static extern int EnumWindows(IntPtr hWnd, IntPtr lParam);
}
#endif
}
}

36
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -1289,25 +1289,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1289,25 +1289,35 @@ namespace ICSharpCode.Decompiler.CSharp
LocalFunctionDeclarationStatement TranslateFunction(ILFunction function)
{
var nestedBuilder = new StatementBuilder(
typeSystem,
exprBuilder.decompilationContext,
function,
settings,
decompileRun,
cancellationToken
);
var astBuilder = exprBuilder.astBuilder;
var method = (MethodDeclaration)astBuilder.ConvertEntity(function.ReducedMethod);
method.Body = nestedBuilder.ConvertAsBlock(function.Body);
Comment prev = null;
foreach (string warning in function.Warnings)
if (function.Method.HasBody)
{
var nestedBuilder = new StatementBuilder(
typeSystem,
exprBuilder.decompilationContext,
function,
settings,
decompileRun,
cancellationToken
);
method.Body = nestedBuilder.ConvertAsBlock(function.Body);
Comment prev = null;
foreach (string warning in function.Warnings)
{
method.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
}
}
else
{
method.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
method.Modifiers |= Modifiers.Extern;
}
CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function);
CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function, function.Method.HasBody);
CSharpDecompiler.RemoveAttribute(method, KnownAttribute.CompilerGenerated);
var stmt = new LocalFunctionDeclarationStatement(method);
stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod));

19
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -56,16 +56,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -56,16 +56,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILFunction f = TransformDelegateConstruction(inst, targetMethod, target, delegateType);
if (f != null && target is IInstructionWithVariableOperand instWithVar)
{
if (instWithVar.Variable.Kind == VariableKind.Local)
var v = instWithVar.Variable;
if (v.Kind == VariableKind.Local)
{
instWithVar.Variable.Kind = VariableKind.DisplayClassLocal;
v.Kind = VariableKind.DisplayClassLocal;
}
if (instWithVar.Variable.IsSingleDefinition && instWithVar.Variable.StoreInstructions.SingleOrDefault() is StLoc store)
if (v.IsSingleDefinition
&& v.StoreInstructions.SingleOrDefault() is StLoc store
&& store.Value is NewObj)
{
if (store.Value is NewObj)
{
instWithVar.Variable.CaptureScope = BlockContainer.FindClosestContainer(store);
}
v.CaptureScope = BlockContainer.FindClosestContainer(store);
}
}
context.StepEndGroup();
@ -116,9 +116,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -116,9 +116,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!(method.HasGeneratedName()
|| method.Name.Contains("$")
|| method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()
|| TransformDisplayClassUsage.IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition)
|| TransformDisplayClassUsage.IsPotentialClosure(
decompiledTypeDefinition, method.DeclaringTypeDefinition)
|| ContainsAnonymousType(method)))
{
return false;
}
return true;
}

35
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -455,22 +455,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -455,22 +455,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILFunction ReadLocalFunctionDefinition(ILFunction rootFunction, IMethod targetMethod, int skipCount)
{
var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken);
if (!methodDefinition.HasBody())
return null;
var ilReader = context.CreateILReader();
var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
var genericContext = GenericContextFromTypeArguments(targetMethod, skipCount);
if (genericContext == null)
return null;
var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.GetValueOrDefault(), ILFunctionKind.LocalFunction, context.CancellationToken);
ILFunction function;
bool hasBody = methodDefinition.HasBody();
if (!hasBody)
{
function = new ILFunction(targetMethod, 0,
new TypeSystem.GenericContext(genericContext?.ClassTypeParameters, genericContext?.MethodTypeParameters),
new Nop(), ILFunctionKind.LocalFunction);
}
else
{
var ilReader = context.CreateILReader();
var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body,
genericContext.GetValueOrDefault(), ILFunctionKind.LocalFunction,
context.CancellationToken);
}
// Embed the local function into the parent function's ILAst, so that "Show steps" can show
// how the local function body is being transformed.
rootFunction.LocalFunctions.Add(function);
function.DeclarationScope = (BlockContainer)rootFunction.Body;
function.CheckInvariant(ILPhase.Normal);
var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
function.DeclarationScope = null;
if (hasBody)
{
function.DeclarationScope = (BlockContainer)rootFunction.Body;
function.CheckInvariant(ILPhase.Normal);
var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
function.DeclarationScope = null;
}
function.ReducedMethod = ReduceToLocalFunction(function.Method, skipCount);
return function;
}

Loading…
Cancel
Save