diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index e247014f7..fd10936bc 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -482,11 +482,11 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Call: case ILCode.CallGetter: case ILCode.CallSetter: - return TransformCall(false, operand, args); + return TransformCall(false, byteCode, args); case ILCode.Callvirt: case ILCode.CallvirtGetter: case ILCode.CallvirtSetter: - return TransformCall(true, operand, args); + return TransformCall(true, byteCode, args); case ILCode.Ldftn: { Cecil.MethodReference cecilMethod = ((MethodReference)operand); var expr = new Ast.IdentifierExpression(cecilMethod.Name); @@ -745,9 +745,10 @@ namespace ICSharpCode.Decompiler.Ast return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) }; } - AstNode TransformCall(bool isVirtual, object operand, List args) + AstNode TransformCall(bool isVirtual, ILExpression byteCode, List args) { - Cecil.MethodReference cecilMethod = ((MethodReference)operand); + Cecil.MethodReference cecilMethod = (MethodReference)byteCode.Operand; + Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve(); Ast.Expression target; List methodArgs = new List(args); if (cecilMethod.HasThis) { @@ -760,6 +761,17 @@ namespace ICSharpCode.Decompiler.Ast target = ((DirectionExpression)target).Expression; target.Remove(); // detach from DirectionExpression } + if (cecilMethodDef != null && cecilMethodDef.DeclaringType.IsInterface) { + TypeReference tr = byteCode.Arguments[0].InferredType; + if (tr != null) { + TypeDefinition td = tr.Resolve(); + if (td != null && !td.IsInterface) { + // Calling an interface method on a non-interface object: + // we need to introduce an explicit cast + target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); + } + } + } } else { target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType) }; } @@ -789,8 +801,7 @@ namespace ICSharpCode.Decompiler.Ast return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last()); } - // Resolve the method to figure out whether it is an accessor: - Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve(); + // Test whether the method is an accessor: if (cecilMethodDef != null) { if (cecilMethodDef.IsGetter && methodArgs.Count == 0) { foreach (var prop in cecilMethodDef.DeclaringType.Properties) { diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index f8de12492..1f9951789 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -126,12 +126,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms )); #region using + static Expression InvokeDispose(Expression identifier) + { + return new Choice { + identifier.Invoke("Dispose"), + identifier.Clone().CastTo(new TypePattern(typeof(IDisposable))).Invoke("Dispose") + }; + } + static readonly AstNode usingTryCatchPattern = new TryCatchStatement { TryBlock = new AnyNode("body"), FinallyBlock = new BlockStatement { new Choice { { "valueType", - new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose")) + new ExpressionStatement(InvokeDispose(new NamedNode("ident", new IdentifierExpression()))) }, { "referenceType", new IfElseStatement { @@ -141,7 +149,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms new NullReferenceExpression() ), TrueStatement = new BlockStatement { - new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose")) + new ExpressionStatement(InvokeDispose(new Backreference("ident"))) } } } diff --git a/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs b/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs new file mode 100644 index 000000000..852551773 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs @@ -0,0 +1,37 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; + +public class CallOverloadedMethod +{ + public void OverloadedMethod(object a) + { + } + + public void OverloadedMethod(int? a) + { + } + + public void OverloadedMethod(string a) + { + } + + public void Call() + { + this.OverloadedMethod("(string)"); + this.OverloadedMethod((object)"(object)"); + this.OverloadedMethod(5); + this.OverloadedMethod((object)5); + this.OverloadedMethod(5L); + this.OverloadedMethod((object)null); + this.OverloadedMethod((string)null); + this.OverloadedMethod((int?)null); + } + + public void CallMethodUsingInterface(List list) + { + ((ICollection)list).Clear(); + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index d2ccdaff4..70f17e390 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -52,6 +52,7 @@ +