Browse Source

Fix #2196: Add support for extern local functions.

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

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

@ -18,6 +18,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
#if CS90
using System.Runtime.InteropServices;
#endif
namespace LocalFunctions 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
} }
} }

16
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -1288,6 +1288,11 @@ namespace ICSharpCode.Decompiler.CSharp
} }
LocalFunctionDeclarationStatement TranslateFunction(ILFunction function) LocalFunctionDeclarationStatement TranslateFunction(ILFunction function)
{
var astBuilder = exprBuilder.astBuilder;
var method = (MethodDeclaration)astBuilder.ConvertEntity(function.ReducedMethod);
if (function.Method.HasBody)
{ {
var nestedBuilder = new StatementBuilder( var nestedBuilder = new StatementBuilder(
typeSystem, typeSystem,
@ -1297,8 +1302,7 @@ namespace ICSharpCode.Decompiler.CSharp
decompileRun, decompileRun,
cancellationToken cancellationToken
); );
var astBuilder = exprBuilder.astBuilder;
var method = (MethodDeclaration)astBuilder.ConvertEntity(function.ReducedMethod);
method.Body = nestedBuilder.ConvertAsBlock(function.Body); method.Body = nestedBuilder.ConvertAsBlock(function.Body);
Comment prev = null; Comment prev = null;
@ -1306,8 +1310,14 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
method.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment); method.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
} }
}
else
{
method.Modifiers |= Modifiers.Extern;
}
CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function); CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function, function.Method.HasBody);
CSharpDecompiler.RemoveAttribute(method, KnownAttribute.CompilerGenerated); CSharpDecompiler.RemoveAttribute(method, KnownAttribute.CompilerGenerated);
var stmt = new LocalFunctionDeclarationStatement(method); var stmt = new LocalFunctionDeclarationStatement(method);
stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod)); stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod));

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

@ -56,16 +56,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILFunction f = TransformDelegateConstruction(inst, targetMethod, target, delegateType); ILFunction f = TransformDelegateConstruction(inst, targetMethod, target, delegateType);
if (f != null && target is IInstructionWithVariableOperand instWithVar) 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) v.CaptureScope = BlockContainer.FindClosestContainer(store);
{
instWithVar.Variable.CaptureScope = BlockContainer.FindClosestContainer(store);
}
} }
} }
context.StepEndGroup(); context.StepEndGroup();
@ -116,9 +116,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!(method.HasGeneratedName() if (!(method.HasGeneratedName()
|| method.Name.Contains("$") || method.Name.Contains("$")
|| method.IsCompilerGeneratedOrIsInCompilerGeneratedClass() || method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()
|| TransformDisplayClassUsage.IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition) || TransformDisplayClassUsage.IsPotentialClosure(
decompiledTypeDefinition, method.DeclaringTypeDefinition)
|| ContainsAnonymousType(method))) || ContainsAnonymousType(method)))
{
return false; return false;
}
return true; return true;
} }

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

@ -455,22 +455,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILFunction ReadLocalFunctionDefinition(ILFunction rootFunction, IMethod targetMethod, int skipCount) ILFunction ReadLocalFunctionDefinition(ILFunction rootFunction, IMethod targetMethod, int skipCount)
{ {
var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken); 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); var genericContext = GenericContextFromTypeArguments(targetMethod, skipCount);
if (genericContext == null) if (genericContext == null)
return 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 // Embed the local function into the parent function's ILAst, so that "Show steps" can show
// how the local function body is being transformed. // how the local function body is being transformed.
rootFunction.LocalFunctions.Add(function); rootFunction.LocalFunctions.Add(function);
if (hasBody)
{
function.DeclarationScope = (BlockContainer)rootFunction.Body; function.DeclarationScope = (BlockContainer)rootFunction.Body;
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
var nestedContext = new ILTransformContext(context, function); var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext); function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
function.DeclarationScope = null; function.DeclarationScope = null;
}
function.ReducedMethod = ReduceToLocalFunction(function.Method, skipCount); function.ReducedMethod = ReduceToLocalFunction(function.Method, skipCount);
return function; return function;
} }

Loading…
Cancel
Save