Browse Source

Fix #87: missing cast when calling explicit interface implementation.

pull/118/head
Daniel Grunwald 14 years ago
parent
commit
cd630c3fbb
  1. 23
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 12
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  3. 37
      ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs
  4. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

23
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -482,11 +482,11 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Call: case ILCode.Call:
case ILCode.CallGetter: case ILCode.CallGetter:
case ILCode.CallSetter: case ILCode.CallSetter:
return TransformCall(false, operand, args); return TransformCall(false, byteCode, args);
case ILCode.Callvirt: case ILCode.Callvirt:
case ILCode.CallvirtGetter: case ILCode.CallvirtGetter:
case ILCode.CallvirtSetter: case ILCode.CallvirtSetter:
return TransformCall(true, operand, args); return TransformCall(true, byteCode, args);
case ILCode.Ldftn: { case ILCode.Ldftn: {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name); var expr = new Ast.IdentifierExpression(cecilMethod.Name);
@ -745,9 +745,10 @@ namespace ICSharpCode.Decompiler.Ast
return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) }; return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) };
} }
AstNode TransformCall(bool isVirtual, object operand, List<Ast.Expression> args) AstNode TransformCall(bool isVirtual, ILExpression byteCode, List<Ast.Expression> args)
{ {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = (MethodReference)byteCode.Operand;
Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve();
Ast.Expression target; Ast.Expression target;
List<Ast.Expression> methodArgs = new List<Ast.Expression>(args); List<Ast.Expression> methodArgs = new List<Ast.Expression>(args);
if (cecilMethod.HasThis) { if (cecilMethod.HasThis) {
@ -760,6 +761,17 @@ namespace ICSharpCode.Decompiler.Ast
target = ((DirectionExpression)target).Expression; target = ((DirectionExpression)target).Expression;
target.Remove(); // detach from DirectionExpression 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 { } else {
target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType) }; 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()); return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last());
} }
// Resolve the method to figure out whether it is an accessor: // Test whether the method is an accessor:
Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve();
if (cecilMethodDef != null) { if (cecilMethodDef != null) {
if (cecilMethodDef.IsGetter && methodArgs.Count == 0) { if (cecilMethodDef.IsGetter && methodArgs.Count == 0) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) { foreach (var prop in cecilMethodDef.DeclaringType.Properties) {

12
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -126,12 +126,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
)); ));
#region using #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 { static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body"), TryBlock = new AnyNode("body"),
FinallyBlock = new BlockStatement { FinallyBlock = new BlockStatement {
new Choice { new Choice {
{ "valueType", { "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose")) new ExpressionStatement(InvokeDispose(new NamedNode("ident", new IdentifierExpression())))
}, },
{ "referenceType", { "referenceType",
new IfElseStatement { new IfElseStatement {
@ -141,7 +149,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new NullReferenceExpression() new NullReferenceExpression()
), ),
TrueStatement = new BlockStatement { TrueStatement = new BlockStatement {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose")) new ExpressionStatement(InvokeDispose(new Backreference("ident")))
} }
} }
} }

37
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<int> list)
{
((ICollection<int>)list).Clear();
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -52,6 +52,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" /> <Compile Include="CheckedUnchecked.cs" />
<Compile Include="IncrementDecrement.cs" /> <Compile Include="IncrementDecrement.cs" />
<Compile Include="Switch.cs" /> <Compile Include="Switch.cs" />

Loading…
Cancel
Save