diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 90ff838a6..689ab843b 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -783,15 +783,15 @@ namespace ICSharpCode.Decompiler.CSharp TranslatedExpression TranslateFunction(TranslatedExpression objectCreateExpression, TranslatedExpression target, ILFunction function) { - var method = typeSystem.Resolve(function.Method) as IMethod; + var method = typeSystem.Resolve(function.Method)?.MemberDefinition as IMethod; Debug.Assert(method != null); - + // Create AnonymousMethodExpression and prepare parameters AnonymousMethodExpression ame = new AnonymousMethodExpression(); ame.Parameters.AddRange(MakeParameters(method, function)); ame.HasParameterList = true; - - StatementBuilder builder = new StatementBuilder(typeSystem, decompilationContext, method); + var context = new SimpleTypeResolveContext(method); + StatementBuilder builder = new StatementBuilder(typeSystem.GetSpecializingTypeSystem(context), context, method); var body = builder.ConvertAsBlock(function.Body); bool isLambda = false; @@ -1274,12 +1274,17 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitIfInstruction(IfInstruction inst) { var condition = TranslateCondition(inst.Condition); - var targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode()); - var trueBranch = Translate(inst.TrueInst).ConvertTo(targetType, this); - var falseBranch = Translate(inst.FalseInst).ConvertTo(targetType, this); - return new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression) + var trueBranch = Translate(inst.TrueInst); + var falseBranch = Translate(inst.FalseInst); + IType targetType; + if (!trueBranch.Type.Equals(SpecialType.NullType) && !falseBranch.Type.Equals(SpecialType.NullType)) { + targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode()); + } else { + targetType = trueBranch.Type.Equals(SpecialType.NullType) ? falseBranch.Type : trueBranch.Type; + } + return new ConditionalExpression(condition.Expression, trueBranch.ConvertTo(targetType, this).Expression, falseBranch.ConvertTo(targetType, this).Expression) .WithILInstruction(inst) - .WithRR(new ResolveResult(trueBranch.Type)); + .WithRR(new ResolveResult(targetType)); } protected internal override TranslatedExpression VisitAddressOf(AddressOf inst) diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index b6d2e5be6..06dc621c9 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -49,8 +49,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms block.Instructions.RemoveAt(i); continue; } - if (CachedDelegateInitializationWithLocal(inst)) { + bool hasFieldStore; + if (CachedDelegateInitializationWithLocal(inst, out hasFieldStore)) { block.Instructions.RemoveAt(i); + if (hasFieldStore) { + block.Instructions.RemoveAt(i - 1); + } continue; } } @@ -96,7 +100,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method; if (IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod)) { var target = value.Arguments[0]; - var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(decompilationContext); + var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(targetMethod)); var function = ILFunction.Read(localTypeSystem, targetMethod, context.CancellationToken); var contextPrefix = targetMethod.Name; @@ -173,9 +177,48 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; } - bool CachedDelegateInitializationWithLocal(IfInstruction inst) + bool CachedDelegateInitializationWithLocal(IfInstruction inst, out bool hasFieldStore) { - return false; + // [stloc v(ldsfld CachedAnonMethodDelegate)] + // if (comp(ldloc v == ldnull) { + // stloc v(DelegateConstruction) + // [stsfld CachedAnonMethodDelegate(v)] + // } + // ... one usage of v ... + // => + // ... one usage of DelegateConstruction ... + Block trueInst = inst.TrueInst as Block; + var condition = inst.Condition as Comp; + hasFieldStore = false; + if (condition == null || trueInst == null || (trueInst.Instructions.Count != 1 && trueInst.Instructions.Count != 2) || !inst.FalseInst.MatchNop()) + return false; + ILVariable v; + ILInstruction value, value2; + var storeInst = trueInst.Instructions[0]; + var optionalFieldStore = trueInst.Instructions.ElementAtOrDefault(1); + if (!condition.Left.MatchLdLoc(out v) || !condition.Right.MatchLdNull()) + return false; + if (!storeInst.MatchStLoc(v, out value)) + return false; + if (optionalFieldStore != null) { + IField field, field2; + if (!optionalFieldStore.MatchStsFld(out value2, out field) || !value2.MatchLdLoc(v) || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) + return false; + var storeBeforeIf = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex - 1) as StLoc; + if (storeBeforeIf == null || storeBeforeIf.Variable != v || !storeBeforeIf.Value.MatchLdsFld(out field2) || !field.Equals(field2)) + return false; + hasFieldStore = true; + } + if (!IsDelegateConstruction(value as NewObj, true)) + return false; + var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1); + if (nextInstruction == null) + return false; + var usages = nextInstruction.Descendants.OfType().Where(i => i.Variable == v).ToArray(); + if (usages.Length != 1) + return false; + usages[0].ReplaceWith(value); + return true; } } } diff --git a/ICSharpCode.Decompiler/NRExtensions.cs b/ICSharpCode.Decompiler/NRExtensions.cs index ff2c2cb72..ec437bcfb 100644 --- a/ICSharpCode.Decompiler/NRExtensions.cs +++ b/ICSharpCode.Decompiler/NRExtensions.cs @@ -33,7 +33,8 @@ namespace ICSharpCode.Decompiler IMethod method = decompilationContext.CurrentMember as IMethod; if (method != null) methodTypeParameters = method.TypeArguments; - + if (typeSystem is SpecializingDecompilerTypeSystem) + typeSystem = ((SpecializingDecompilerTypeSystem)typeSystem).Context; if ((classTypeParameters != null && classTypeParameters.Count > 0) || (methodTypeParameters != null && methodTypeParameters.Count > 0)) return new SpecializingDecompilerTypeSystem(typeSystem, new TypeParameterSubstitution(classTypeParameters, methodTypeParameters)); else diff --git a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs index 86777361d..c9ea66877 100644 --- a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs @@ -38,6 +38,10 @@ namespace ICSharpCode.Decompiler this.context = context; this.substitution = substitution; } + + internal IDecompilerTypeSystem Context { + get { return context; } + } public ICompilation Compilation { get { return context.Compilation; }