Browse Source

Fix #346: incorrect type inference for if statement on ref bool parameter

pull/345/merge
Daniel Grunwald 14 years ago
parent
commit
1b6d1088e8
  1. 22
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  2. 20
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs
  3. 8
      ICSharpCode.Decompiler/Tests/ValueTypes.cs

22
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -385,23 +385,29 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldobj: case ILCode.Ldobj:
{ {
TypeReference type = (TypeReference)expr.Operand; TypeReference type = (TypeReference)expr.Operand;
if (expectedType != null) { var argType = InferTypeForExpression(expr.Arguments[0], null);
int infoAmount = GetInformationAmount(expectedType); if (argType is PointerType || argType is ByReferenceType) {
var elementType = ((TypeSpecification)argType).ElementType;
int infoAmount = GetInformationAmount(elementType);
if (infoAmount == 1 && GetInformationAmount(type) == 8) { if (infoAmount == 1 && GetInformationAmount(type) == 8) {
// A bool can be loaded from both bytes and sbytes. // A bool can be loaded from both bytes and sbytes.
type = expectedType; type = elementType;
} }
if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) { if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) {
// An integer can be loaded as another integer of the same size. // An integer can be loaded as another integer of the same size.
// For integers smaller than 32 bit, the signs must match (as loading performs sign extension) // For integers smaller than 32 bit, the signs must match (as loading performs sign extension)
if (infoAmount >= 32 || IsSigned(expectedType) == IsSigned(type)) bool? elementTypeIsSigned = IsSigned(elementType);
type = expectedType; bool? typeIsSigned = IsSigned(type);
if (elementTypeIsSigned != null && typeIsSigned != null) {
if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned)
type = elementType;
} }
} }
if (forceInferChildren) {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
} }
if (argType is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
else
InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type));
return type; return type;
} }
case ILCode.Stobj: case ILCode.Stobj:

20
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -33,6 +33,21 @@ public class UnsafeCode
return *(long*)(&d); return *(long*)(&d);
} }
public unsafe double ConvertLongToDouble(long d)
{
return *(double*)(&d);
}
public unsafe int ConvertFloatToInt(float d)
{
return *(int*)(&d);
}
public unsafe float ConvertIntToFloat(int d)
{
return *(float*)(&d);
}
public unsafe void PassRefParameterAsPointer(ref int p) public unsafe void PassRefParameterAsPointer(ref int p)
{ {
fixed (int* ptr = &p) fixed (int* ptr = &p)
@ -48,7 +63,8 @@ public class UnsafeCode
public unsafe void AddressInMultiDimensionalArray(double[,] matrix) public unsafe void AddressInMultiDimensionalArray(double[,] matrix)
{ {
fixed (double* ptr = &matrix[1, 2]) { fixed (double* ptr = &matrix[1, 2])
{
this.PointerReferenceExpression(ptr); this.PointerReferenceExpression(ptr);
} }
} }
@ -58,7 +74,7 @@ public class UnsafeCode
fixed (char* ptr = text) fixed (char* ptr = text)
{ {
char* ptr2 = ptr; char* ptr2 = ptr;
while (*ptr2 != 0) while (*ptr2 != '\0')
{ {
*ptr2 = 'A'; *ptr2 = 'A';
ptr2++; ptr2++;

8
ICSharpCode.Decompiler/Tests/ValueTypes.cs

@ -160,4 +160,12 @@ public static class ValueTypes
s.SetField(); s.SetField();
return p; return p;
} }
public static void UseRefBoolInCondition(ref bool x)
{
if (x)
{
Console.WriteLine("true");
}
}
} }

Loading…
Cancel
Save