From af155c788e07a4f09b6c8d73420368a7ed3de0c5 Mon Sep 17 00:00:00 2001 From: Pent Ploompuu Date: Tue, 24 May 2011 01:02:42 +0300 Subject: [PATCH] Type analysis support for operators on nullable values --- ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs | 1 + ICSharpCode.Decompiler/ILAst/ILCodes.cs | 9 +++++++-- ICSharpCode.Decompiler/ILAst/ILInlining.cs | 4 +++- ICSharpCode.Decompiler/ILAst/NullableOperators.cs | 5 ++++- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 9 +++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 69e1721aa..ca5e5f4c8 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -751,6 +751,7 @@ namespace ICSharpCode.Decompiler.Ast return new ParenthesizedExpression(arg1); case ILCode.AddressOf: return MakeRef(arg1); + case ILCode.ValueOf: return arg1; default: throw new Exception("Unknown OpCode: " + byteCode.Code); } diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 46a269259..8216a1b60 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst InitArray, // Array Initializer /// - /// 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 /// Wrap, @@ -316,7 +316,12 @@ namespace ICSharpCode.Decompiler.ILAst /// 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(...))" /// - AddressOf + AddressOf, + /// Simulates getting the value of the nullable argument in comparisons involving nullable values + /// + /// 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(...), ...)" + /// + ValueOf, } public static class ILCodeUtil diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs index d839f41ef..31519b75e 100644 --- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs +++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs @@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.ILAst } /// - /// Determines whether it is save to move 'expressionBeingMoved' past 'expr' + /// Determines whether it is safe to move 'expressionBeingMoved' past 'expr' /// bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved) { @@ -427,6 +427,8 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Ldflda: case ILCode.Ldsflda: case ILCode.Ldelema: + case ILCode.AddressOf: + case ILCode.ValueOf: // address-loading instructions are safe if their arguments are safe foreach (ILExpression arg in expr.Arguments) { if (!IsSafeForInlineOver(arg, expressionBeingMoved)) diff --git a/ICSharpCode.Decompiler/ILAst/NullableOperators.cs b/ICSharpCode.Decompiler/ILAst/NullableOperators.cs index e830484bf..400a853f5 100644 --- a/ICSharpCode.Decompiler/ILAst/NullableOperators.cs +++ b/ICSharpCode.Decompiler/ILAst/NullableOperators.cs @@ -217,7 +217,10 @@ namespace ICSharpCode.Decompiler.ILAst 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; } } diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 819b5f7ae..9da8e0021 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -487,6 +487,15 @@ namespace ICSharpCode.Decompiler.ILAst TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); 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 #region Arithmetic instructions case ILCode.Not: // bitwise complement