Browse Source

Type analysis support for operators on nullable values

pull/205/head
Pent Ploompuu 14 years ago
parent
commit
af155c788e
  1. 1
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 9
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  3. 4
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  4. 5
      ICSharpCode.Decompiler/ILAst/NullableOperators.cs
  5. 9
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

1
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -751,6 +751,7 @@ namespace ICSharpCode.Decompiler.Ast
return new ParenthesizedExpression(arg1); return new ParenthesizedExpression(arg1);
case ILCode.AddressOf: case ILCode.AddressOf:
return MakeRef(arg1); return MakeRef(arg1);
case ILCode.ValueOf: return arg1;
default: default:
throw new Exception("Unknown OpCode: " + byteCode.Code); throw new Exception("Unknown OpCode: " + byteCode.Code);
} }

9
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst
InitArray, // Array Initializer InitArray, // Array Initializer
/// <summary> /// <summary>
/// Defines a barrier between the parent opcode and argument opcode that prevents combining them /// Defines a barrier between the parent expression and the argument expression that prevents combining them
/// </summary> /// </summary>
Wrap, Wrap,
@ -316,7 +316,12 @@ namespace ICSharpCode.Decompiler.ILAst
/// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays. /// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays.
/// Also used when inlining a method call on a value type: "stloc(v, ...); call(M, ldloca(v));" becomes "call(M, AddressOf(...))" /// Also used when inlining a method call on a value type: "stloc(v, ...); call(M, ldloca(v));" becomes "call(M, AddressOf(...))"
/// </remarks> /// </remarks>
AddressOf AddressOf,
/// <summary>Simulates getting the value of the nullable argument in comparisons involving nullable values</summary>
/// <remarks>
/// For example "stloc(v1, ...); stloc(v2, ...); logicand(ceq(call(Nullable`1::GetValueOrDefault, ldloca(v1)), ldloc(v2)), callgetter(Nullable`1::get_HasValue, ldloca(v1)))" becomes "ceq(ValueOf(...), ...)"
/// </remarks>
ValueOf,
} }
public static class ILCodeUtil public static class ILCodeUtil

4
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
/// <summary> /// <summary>
/// Determines whether it is save to move 'expressionBeingMoved' past 'expr' /// Determines whether it is safe to move 'expressionBeingMoved' past 'expr'
/// </summary> /// </summary>
bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved) bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved)
{ {
@ -427,6 +427,8 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldflda: case ILCode.Ldflda:
case ILCode.Ldsflda: case ILCode.Ldsflda:
case ILCode.Ldelema: case ILCode.Ldelema:
case ILCode.AddressOf:
case ILCode.ValueOf:
// address-loading instructions are safe if their arguments are safe // address-loading instructions are safe if their arguments are safe
foreach (ILExpression arg in expr.Arguments) { foreach (ILExpression arg in expr.Arguments) {
if (!IsSafeForInlineOver(arg, expressionBeingMoved)) if (!IsSafeForInlineOver(arg, expressionBeingMoved))

5
ICSharpCode.Decompiler/ILAst/NullableOperators.cs

@ -217,7 +217,10 @@ namespace ICSharpCode.Decompiler.ILAst
public override ILExpression BuildNew(ref PatternMatcher pm, ILExpression[] args) public override ILExpression BuildNew(ref PatternMatcher pm, ILExpression[] args)
{ {
return new ILExpression(this.code, this.b ? pm.B : pm.A, args); var v = this.b ? pm.B : pm.A;
var e = new ILExpression(ILCode.Ldloc, v, args);
if (v.Type.Name == "Nullable`1" && v.Type.Namespace == "System") e = new ILExpression(ILCode.ValueOf, null, e);
return e;
} }
} }

9
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -487,6 +487,15 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType));
return t != null ? new ByReferenceType(t) : null; return t != null ? new ByReferenceType(t) : null;
} }
case ILCode.ValueOf: {
GenericInstanceType t = null;
if (expectedType != null) {
t = new GenericInstanceType(new TypeReference("System", "Nullable`1", module, module.TypeSystem.Corlib));
t.GenericArguments.Add(expectedType);
}
t = InferTypeForExpression(expr.Arguments[0], t) as GenericInstanceType;
return t == null || t.Name != "Nullable`1" || t.Namespace != "System" ? null : t.GenericArguments[0];
}
#endregion #endregion
#region Arithmetic instructions #region Arithmetic instructions
case ILCode.Not: // bitwise complement case ILCode.Not: // bitwise complement

Loading…
Cancel
Save