Browse Source

Improve local-function detection to minimize false positives.

pull/1586/head
Siegfried Pammer 6 years ago
parent
commit
f10ab69328
  1. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 29
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1877,7 +1877,7 @@ namespace ICSharpCode.Decompiler.CSharp
// needs to be consistent with logic in ILReader.CreateILVarable(ParameterDefinition) // needs to be consistent with logic in ILReader.CreateILVarable(ParameterDefinition)
pd.Name = "P_" + i; pd.Name = "P_" + i;
// if this is a local function, we have to skip the parameters for closure references // if this is a local function, we have to skip the parameters for closure references
if (settings.LocalFunctions && function.Kind == ILFunctionKind.LocalFunction && IL.Transforms.LocalFunctionDecompiler.IsClosureParameter(parameter)) if (settings.LocalFunctions && function.Kind == ILFunctionKind.LocalFunction && IL.Transforms.LocalFunctionDecompiler.IsClosureParameter(parameter, decompilationContext))
break; break;
} }
if (settings.AnonymousTypes && parameter.Type.ContainsAnonymousType()) if (settings.AnonymousTypes && parameter.Type.ContainsAnonymousType())

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

@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
class LocalFunctionDecompiler : IILTransform class LocalFunctionDecompiler : IILTransform
{ {
ILTransformContext context; ILTransformContext context;
ITypeResolveContext resolveContext;
struct LocalFunctionInfo struct LocalFunctionInfo
{ {
@ -64,6 +65,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!context.Settings.LocalFunctions) if (!context.Settings.LocalFunctions)
return; return;
this.context = context; this.context = context;
this.resolveContext = new SimpleTypeResolveContext(function.Method);
var localFunctions = new Dictionary<MethodDefinitionHandle, LocalFunctionInfo>(); var localFunctions = new Dictionary<MethodDefinitionHandle, LocalFunctionInfo>();
var cancellationToken = context.CancellationToken; var cancellationToken = context.CancellationToken;
// Find all local functions declared inside this method, including nested local functions or local functions declared in lambdas. // Find all local functions declared inside this method, including nested local functions or local functions declared in lambdas.
@ -161,11 +163,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return a.Ancestors.OfType<T>().FirstOrDefault(ancestorsOfB.Contains); return a.Ancestors.OfType<T>().FirstOrDefault(ancestorsOfB.Contains);
} }
internal static bool IsClosureParameter(IParameter parameter) internal static bool IsClosureParameter(IParameter parameter, ITypeResolveContext context)
{ {
return parameter.IsRef if (!parameter.IsRef)
&& ((ByReferenceType)parameter.Type).ElementType return false;
.GetDefinition()?.IsCompilerGenerated() == true; var type = ((ByReferenceType)parameter.Type).ElementType.GetDefinition();
return type != null
&& type.Kind == TypeKind.Struct
&& TransformDisplayClassUsage.IsPotentialClosure(context.CurrentTypeDefinition, type);
} }
static IType UnwrapByRef(IType type) static IType UnwrapByRef(IType type)
@ -190,7 +195,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
int parametersToRemove = 0; int parametersToRemove = 0;
for (int i = method.Parameters.Count - 1; i >= 0; i--) { for (int i = method.Parameters.Count - 1; i >= 0; i--) {
if (!IsClosureParameter(method.Parameters[i])) if (!IsClosureParameter(method.Parameters[i], resolveContext))
break; break;
parametersToRemove++; parametersToRemove++;
} }
@ -213,23 +218,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
int argumentCount = useSite.Arguments.Count; int argumentCount = useSite.Arguments.Count;
int reducedArgumentCount = argumentCount - (reducedMethod.NumberOfCompilerGeneratedParameters + firstArgumentIndex); int reducedArgumentCount = argumentCount - (reducedMethod.NumberOfCompilerGeneratedParameters + firstArgumentIndex);
replacement.Arguments.AddRange(useSite.Arguments.Skip(firstArgumentIndex).Take(reducedArgumentCount)); replacement.Arguments.AddRange(useSite.Arguments.Skip(firstArgumentIndex).Take(reducedArgumentCount));
// copy flags: // copy flags
replacement.ConstrainedTo = useSite.ConstrainedTo; replacement.ConstrainedTo = useSite.ConstrainedTo;
replacement.ILStackWasEmpty = useSite.ILStackWasEmpty; replacement.ILStackWasEmpty = useSite.ILStackWasEmpty;
replacement.IsTail = useSite.IsTail; replacement.IsTail = useSite.IsTail;
// copy IL ranges // copy IL ranges
replacement = replacement.WithILRange(useSite); replacement.AddILRange(useSite);
if (wasInstanceCall) { if (wasInstanceCall) {
replacement = replacement.WithILRange(useSite.Arguments[0]); replacement.AddILRange(useSite.Arguments[0]);
} }
for (int i = 0; i < reducedMethod.NumberOfCompilerGeneratedParameters; i++) { for (int i = 0; i < reducedMethod.NumberOfCompilerGeneratedParameters; i++) {
replacement = replacement.WithILRange(useSite.Arguments[argumentCount - i - 1]); replacement.AddILRange(useSite.Arguments[argumentCount - i - 1]);
} }
useSite.ReplaceWith(replacement); useSite.ReplaceWith(replacement);
} }
void DetermineCaptureAndDeclarationScope(ILFunction function, CallInstruction useSite) void DetermineCaptureAndDeclarationScope(ILFunction function, CallInstruction useSite)
{ {
int firstArgumentIndex = function.Method.IsStatic ? 0 : 1;
for (int i = useSite.Arguments.Count - 1; i >= 0; i--) { for (int i = useSite.Arguments.Count - 1; i >= 0; i--) {
var arg = useSite.Arguments[i]; var arg = useSite.Arguments[i];
ILVariable closureVar; ILVariable closureVar;
@ -239,6 +245,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break; break;
if (!TransformDisplayClassUsage.IsPotentialClosure(context, UnwrapByRef(closureVar.Type).GetDefinition())) if (!TransformDisplayClassUsage.IsPotentialClosure(context, UnwrapByRef(closureVar.Type).GetDefinition()))
break; break;
if (i - firstArgumentIndex >= 0) {
Debug.Assert(i - firstArgumentIndex < function.Method.Parameters.Count && IsClosureParameter(function.Method.Parameters[i - firstArgumentIndex], resolveContext));
}
if (closureVar.AddressCount == 0 && closureVar.StoreInstructions.Count == 0) if (closureVar.AddressCount == 0 && closureVar.StoreInstructions.Count == 0)
continue; continue;
// determine the capture scope of closureVar and the declaration scope of the function // determine the capture scope of closureVar and the declaration scope of the function
@ -262,7 +271,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
var opCode = inst.Arguments[1].OpCode; var opCode = inst.Arguments[1].OpCode;
return (opCode == OpCode.LdFtn || opCode == OpCode.LdVirtFtn) return opCode == OpCode.LdFtn
&& IsLocalFunctionMethod(((IInstructionWithMethodOperand)inst.Arguments[1]).Method, context); && IsLocalFunctionMethod(((IInstructionWithMethodOperand)inst.Arguments[1]).Method, context);
} }

2
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (IsClosure(v, out ITypeDefinition closureType, out var inst)) { if (IsClosure(v, out ITypeDefinition closureType, out var inst)) {
AddOrUpdateDisplayClass(f, v, closureType, inst, localFunctionClosureParameter: false); AddOrUpdateDisplayClass(f, v, closureType, inst, localFunctionClosureParameter: false);
} }
if (context.Settings.LocalFunctions && f.Kind == ILFunctionKind.LocalFunction && v.Kind == VariableKind.Parameter && v.Index > -1 && f.Method.Parameters[v.Index.Value] is IParameter p && LocalFunctionDecompiler.IsClosureParameter(p)) { if (context.Settings.LocalFunctions && f.Kind == ILFunctionKind.LocalFunction && v.Kind == VariableKind.Parameter && v.Index > -1 && f.Method.Parameters[v.Index.Value] is IParameter p && LocalFunctionDecompiler.IsClosureParameter(p, decompilationContext)) {
AddOrUpdateDisplayClass(f, v, ((ByReferenceType)p.Type).ElementType.GetDefinition(), f.Body, localFunctionClosureParameter: true); AddOrUpdateDisplayClass(f, v, ((ByReferenceType)p.Type).ElementType.GetDefinition(), f.Body, localFunctionClosureParameter: true);
} }
} }

Loading…
Cancel
Save