Browse Source

Add test case for #981, and fix decompilation of ?: operator on StackType.Ref (necessary to make the testcase compile).

pull/1012/head
Daniel Grunwald 8 years ago
parent
commit
87a03bde70
  1. 2
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 21
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/StackTypes.il
  4. 34
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  5. 3
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

2
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void StackTypes([Values(false, true)] bool force32Bit)
{
CompilerOptions compiler = CompilerOptions.UseDebug;
CompilerOptions compiler = CompilerOptions.UseRoslyn | CompilerOptions.UseDebug;
AssemblerOptions asm = AssemblerOptions.None;
if (force32Bit) {
compiler |= CompilerOptions.Force32Bit;

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="1.0.0.55" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.6.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="NUnit" Version="2.6.3" />
<PackageReference Include="NUnitTestAdapter" Version="2.0.0" />

21
ICSharpCode.Decompiler.Tests/TestCases/Correctness/StackTypes.il

@ -256,6 +256,27 @@ pointless: @@ -256,6 +256,27 @@ pointless:
ret
}
.method public static void RefOrNull(uint8& r, bool use_null)
{
// Not quite valid IL due to ref<->I mismatch.
// https://github.com/icsharpcode/ILSpy/issues/981
ldarg.1
brtrue push_null
ldarg.0
br done
push_null:
ldc.i4.0
conv.u
done:
call void Program::UseRef(uint8&)
ret
}
.method public static void UseRef(uint8& r)
{
ret
}
.method public static void Print(native int val)
{
ldarg.0

34
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2063,8 +2063,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2063,8 +2063,22 @@ namespace ICSharpCode.Decompiler.CSharp
IType targetType;
if (!trueBranch.Type.Equals(SpecialType.NullType) && !falseBranch.Type.Equals(SpecialType.NullType) && !trueBranch.Type.Equals(falseBranch.Type)) {
targetType = typeInference.GetBestCommonType(new[] { trueBranch.ResolveResult, falseBranch.ResolveResult }, out bool success);
if (!success || targetType.GetStackType() != inst.ResultType)
targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode());
if (!success || targetType.GetStackType() != inst.ResultType) {
// Figure out the target type based on inst.ResultType.
if (inst.ResultType == StackType.Ref) {
// targetType should be a ref-type
if (trueBranch.Type.Kind == TypeKind.ByReference) {
targetType = trueBranch.Type;
} else if (falseBranch.Type.Kind == TypeKind.ByReference) {
targetType = falseBranch.Type;
} else {
// fall back to 'ref byte' if we can't determine a referenced type otherwise
targetType = new ByReferenceType(compilation.FindType(KnownTypeCode.Byte));
}
} else {
targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode());
}
}
} else {
targetType = trueBranch.Type.Equals(SpecialType.NullType) ? falseBranch.Type : trueBranch.Type;
}
@ -2072,9 +2086,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2072,9 +2086,19 @@ namespace ICSharpCode.Decompiler.CSharp
falseBranch = falseBranch.ConvertTo(targetType, this);
rr = new ResolveResult(targetType);
}
return new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression)
.WithILInstruction(inst)
.WithRR(rr);
if (rr.Type.Kind == TypeKind.ByReference) {
// C# conditional ref looks like this:
// ref (arr != null ? ref trueBranch : ref falseBranch);
return new DirectionExpression(FieldDirection.Ref,
new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression)
.WithILInstruction(inst)
.WithRR(new ResolveResult(((ByReferenceType)rr.Type).ElementType))
).WithoutILInstruction().WithRR(rr);
} else {
return new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression)
.WithILInstruction(inst)
.WithRR(rr);
}
}
protected internal override TranslatedExpression VisitAddressOf(AddressOf inst, TranslationContext context)

3
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -198,6 +198,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -198,6 +198,9 @@ namespace ICSharpCode.Decompiler.CSharp
}
return this;
}
if (targetType.Kind == TypeKind.Unknown) {
return this; // don't attempt to insert cast to '?'
}
var compilation = expressionBuilder.compilation;
bool isLifted = type.IsKnownType(KnownTypeCode.NullableOfT) && targetType.IsKnownType(KnownTypeCode.NullableOfT);
IType utype = isLifted ? NullableType.GetUnderlyingType(type) : type;

Loading…
Cancel
Save