From 480ddc0c8f563f2669258364cb1739c1f79aa6cb Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 25 Feb 2018 17:41:47 +0100 Subject: [PATCH] #1055: Use more type hints in ExpressionBuilder. --- .../TestCases/Pretty/TypeAnalysisTests.cs | 5 +++ .../TestCases/Pretty/TypeAnalysisTests.il | 35 ++++++++++++++++--- .../TestCases/Pretty/TypeAnalysisTests.opt.il | 28 ++++++++++++--- .../Pretty/TypeAnalysisTests.opt.roslyn.il | 24 +++++++++++-- .../Pretty/TypeAnalysisTests.roslyn.il | 30 ++++++++++++++-- ICSharpCode.Decompiler/CSharp/CallBuilder.cs | 6 ++-- .../CSharp/ExpressionBuilder.cs | 27 +++++++------- .../CSharp/StatementBuilder.cs | 6 ++-- 8 files changed, 131 insertions(+), 30 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs index 10bef3a73..e8c5fd591 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs @@ -239,5 +239,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { return v; } + + public bool EnumInConditionalOperator(bool b) + { + return string.Equals("", "", b ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il index 49adfa795..0e3b5cb83 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly fpugcpej +.assembly mu5mxl5m { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -20,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module fpugcpej.dll -// MVID: {F42443CE-6C18-4149-B04E-77437B350B2C} +.module mu5mxl5m.dll +// MVID: {DBFE6CB1-ED58-473D-986E-A633C15C8AEE} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01650000 +// Image base: 0x04E10000 // =============== CLASS MEMBERS DECLARATION =================== @@ -821,6 +821,33 @@ IL_000b: ret } // end of method TypeAnalysisTests::ImplicitConversionToDecimal + .method public hidebysig instance bool + EnumInConditionalOperator(bool b) cil managed + { + // Code size 29 (0x1d) + .maxstack 3 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldstr "" + IL_0006: ldstr "" + IL_000b: ldarg.1 + IL_000c: brtrue.s IL_0011 + + IL_000e: ldc.i4.5 + IL_000f: br.s IL_0012 + + IL_0011: ldc.i4.4 + IL_0012: nop + IL_0013: call bool [mscorlib]System.String::Equals(string, + string, + valuetype [mscorlib]System.StringComparison) + IL_0018: stloc.0 + IL_0019: br.s IL_001b + + IL_001b: ldloc.0 + IL_001c: ret + } // end of method TypeAnalysisTests::EnumInConditionalOperator + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il index 74e325a50..fb0c04e29 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly '31uigzt1' +.assembly tbojr2zd { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -20,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module '31uigzt1.dll' -// MVID: {77B7D9D4-A6DF-4CC8-B1E3-7B3B553633FF} +.module tbojr2zd.dll +// MVID: {A417EC21-8726-4629-9E82-47FE9895CD81} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01360000 +// Image base: 0x05150000 // =============== CLASS MEMBERS DECLARATION =================== @@ -566,6 +566,26 @@ IL_0006: ret } // end of method TypeAnalysisTests::ImplicitConversionToDecimal + .method public hidebysig instance bool + EnumInConditionalOperator(bool b) cil managed + { + // Code size 23 (0x17) + .maxstack 8 + IL_0000: ldstr "" + IL_0005: ldstr "" + IL_000a: ldarg.1 + IL_000b: brtrue.s IL_0010 + + IL_000d: ldc.i4.5 + IL_000e: br.s IL_0011 + + IL_0010: ldc.i4.4 + IL_0011: call bool [mscorlib]System.String::Equals(string, + string, + valuetype [mscorlib]System.StringComparison) + IL_0016: ret + } // end of method TypeAnalysisTests::EnumInConditionalOperator + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il index 7856b67e0..a5bd19a80 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module TypeAnalysisTests.dll -// MVID: {6215C6B8-0FF3-4C9E-999F-BE9720986F05} +// MVID: {A4070ABB-2C83-48F4-BD1F-AFD93DD2EF34} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x03030000 +// Image base: 0x00B60000 // =============== CLASS MEMBERS DECLARATION =================== @@ -568,6 +568,26 @@ IL_0006: ret } // end of method TypeAnalysisTests::ImplicitConversionToDecimal + .method public hidebysig instance bool + EnumInConditionalOperator(bool b) cil managed + { + // Code size 23 (0x17) + .maxstack 8 + IL_0000: ldstr "" + IL_0005: ldstr "" + IL_000a: ldarg.1 + IL_000b: brtrue.s IL_0010 + + IL_000d: ldc.i4.5 + IL_000e: br.s IL_0011 + + IL_0010: ldc.i4.4 + IL_0011: call bool [mscorlib]System.String::Equals(string, + string, + valuetype [mscorlib]System.StringComparison) + IL_0016: ret + } // end of method TypeAnalysisTests::EnumInConditionalOperator + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il index d1476c7eb..87e4d2a48 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module TypeAnalysisTests.dll -// MVID: {3A10F4E7-88B8-4945-8775-A3643132F64B} +// MVID: {052B0385-6029-49B3-BCD3-93C26CCA8399} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01720000 +// Image base: 0x03100000 // =============== CLASS MEMBERS DECLARATION =================== @@ -820,6 +820,32 @@ IL_000b: ret } // end of method TypeAnalysisTests::ImplicitConversionToDecimal + .method public hidebysig instance bool + EnumInConditionalOperator(bool b) cil managed + { + // Code size 28 (0x1c) + .maxstack 3 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldstr "" + IL_0006: ldstr "" + IL_000b: ldarg.1 + IL_000c: brtrue.s IL_0011 + + IL_000e: ldc.i4.5 + IL_000f: br.s IL_0012 + + IL_0011: ldc.i4.4 + IL_0012: call bool [mscorlib]System.String::Equals(string, + string, + valuetype [mscorlib]System.StringComparison) + IL_0017: stloc.0 + IL_0018: br.s IL_001a + + IL_001a: ldloc.0 + IL_001b: ret + } // end of method TypeAnalysisTests::EnumInConditionalOperator + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index b76b3fbdc..89d8bdd7a 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp bool isExpandedForm = false; for (int i = 0; i < method.Parameters.Count; i++) { var parameter = expectedParameters[i]; - var arg = expressionBuilder.Translate(callArguments[firstParamIndex + i]); + var arg = expressionBuilder.Translate(callArguments[firstParamIndex + i], parameter.Type); if (parameter.IsParams && i + 1 == method.Parameters.Count) { // Parameter is marked params // If the argument is an array creation, inline all elements into the call and add missing default values. @@ -438,11 +438,11 @@ namespace ICSharpCode.Decompiler.CSharp TranslatedExpression target; IType targetType; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { - target = expressionBuilder.Translate(inst.Arguments[0]); targetType = method.Parameters[0].Type; + target = expressionBuilder.Translate(inst.Arguments[0], targetType); } else { - target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); targetType = method.DeclaringType; + target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); } var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index be170e9f3..7100ff3ba 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -274,9 +274,10 @@ namespace ICSharpCode.Decompiler.CSharp if (ShouldDisplayAsHex(inst.Value, inst.Parent)) { literalValue = $"0x{inst.Value:X}"; } - return new PrimitiveExpression(inst.Value, literalValue) + var expr = new PrimitiveExpression(inst.Value, literalValue) .WithILInstruction(inst) .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), inst.Value)); + return AdjustConstantExpressionToType(expr, context.TypeHint); } protected internal override TranslatedExpression VisitLdcI8(LdcI8 inst, TranslationContext context) @@ -461,7 +462,7 @@ namespace ICSharpCode.Decompiler.CSharp if (inst.Kind == ComparisonKind.Equality && inst.Right.MatchLdcI4(0)) { // lifted logic.not var targetType = NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean)); - var arg = Translate(inst.Left).ConvertTo(targetType, this); + var arg = Translate(inst.Left, targetType).ConvertTo(targetType, this); return new UnaryOperatorExpression(UnaryOperatorType.Not, arg.Expression) .WithRR(new OperatorResolveResult(targetType, ExpressionType.Not, arg.ResolveResult)) .WithILInstruction(inst); @@ -1509,7 +1510,7 @@ namespace ICSharpCode.Decompiler.CSharp .WithILInstruction(target) .WithRR(new ThisResolveResult(member.DeclaringType, nonVirtualInvocation)); } else { - var translatedTarget = Translate(target); + var translatedTarget = Translate(target, constrainedTo ?? member.DeclaringType); if (CallInstruction.ExpectedTypeForThisPointer(constrainedTo ?? member.DeclaringType) == StackType.Ref && translatedTarget.Type.GetStackType().IsIntegerType()) { // when accessing members on value types, ensure we use a reference and not a pointer translatedTarget = translatedTarget.ConvertTo(new ByReferenceType(constrainedTo ?? member.DeclaringType), this); @@ -1874,11 +1875,11 @@ namespace ICSharpCode.Decompiler.CSharp if (lastElement.Indices?.Length > 0) { var indexer = new IndexerExpression(null, lastElement.Indices.SelectArray(i => Translate(i is LdLoc ld ? indexVariables[ld.Variable] : i).Expression)) .WithILInstruction(inst).WithRR(memberRR); - elementsStack.Peek().Add(Assignment(indexer, Translate(info.Values.Single()))); + elementsStack.Peek().Add(Assignment(indexer, Translate(info.Values.Single(), typeHint: indexer.Type))); } else { var target = new IdentifierExpression(lastElement.Member.Name) .WithILInstruction(inst).WithRR(memberRR); - elementsStack.Peek().Add(Assignment(target, Translate(info.Values.Single()))); + elementsStack.Peek().Add(Assignment(target, Translate(info.Values.Single(), typeHint: target.Type))); } break; } @@ -1907,11 +1908,13 @@ namespace ICSharpCode.Decompiler.CSharp Expression MakeInitializerElements(List values, IList parameters) { - if (values.Count == 1) - return Translate(values[0]).ConvertTo(parameters[0].Type, this); + if (values.Count == 1) { + return Translate(values[0], typeHint: parameters[0].Type).ConvertTo(parameters[0].Type, this); + } var expressions = new Expression[values.Count]; - for (int i = 0; i < values.Count; i++) - expressions[i] = Translate(values[i]).ConvertTo(parameters[i].Type, this); + for (int i = 0; i < values.Count; i++) { + expressions[i] = Translate(values[i], typeHint: parameters[i].Type).ConvertTo(parameters[i].Type, this); + } return new ArrayInitializerExpression(expressions); } @@ -1952,7 +1955,7 @@ namespace ICSharpCode.Decompiler.CSharp container.Peek().Elements.Add(aie); container.Push(aie); } - var val = Translate(value).ConvertTo(type, this, allowImplicitConversion: true); + var val = Translate(value, typeHint: type).ConvertTo(type, this, allowImplicitConversion: true); container.Peek().Elements.Add(val); elementResolveResults.Add(val.ResolveResult); while (container.Count > 0 && container.Peek().Elements.Count == dimensionSizes[container.Count - 1]) { @@ -2053,8 +2056,8 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitIfInstruction(IfInstruction inst, TranslationContext context) { var condition = TranslateCondition(inst.Condition); - var trueBranch = Translate(inst.TrueInst); - var falseBranch = Translate(inst.FalseInst); + var trueBranch = Translate(inst.TrueInst, typeHint: context.TypeHint); + var falseBranch = Translate(inst.FalseInst, typeHint: context.TypeHint); BinaryOperatorType op = BinaryOperatorType.Any; TranslatedExpression rhs = default(TranslatedExpression); diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 5fea9b7f8..44d117447 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -264,7 +264,7 @@ namespace ICSharpCode.Decompiler.CSharp return new YieldBreakStatement(); else if (!inst.Value.MatchNop()) { IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentFunction.ReturnType; - return new ReturnStatement(exprBuilder.Translate(inst.Value).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true)); + return new ReturnStatement(exprBuilder.Translate(inst.Value, typeHint: targetType).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true)); } else return new ReturnStatement(); } @@ -290,7 +290,7 @@ namespace ICSharpCode.Decompiler.CSharp { var elementType = currentFunction.ReturnType.GetElementTypeFromIEnumerable(typeSystem.Compilation, true, out var isGeneric); return new YieldReturnStatement { - Expression = exprBuilder.Translate(inst.Value).ConvertTo(elementType, exprBuilder) + Expression = exprBuilder.Translate(inst.Value, typeHint: elementType).ConvertTo(elementType, exprBuilder) }; } @@ -706,7 +706,7 @@ namespace ICSharpCode.Decompiler.CSharp if (inst.Init.OpCode == OpCode.ArrayToPointer) { initExpr = exprBuilder.Translate(((ArrayToPointer)inst.Init).Array); } else { - initExpr = exprBuilder.Translate(inst.Init).ConvertTo(inst.Variable.Type, exprBuilder); + initExpr = exprBuilder.Translate(inst.Init, typeHint: inst.Variable.Type).ConvertTo(inst.Variable.Type, exprBuilder); } fixedStmt.Variables.Add(new VariableInitializer(inst.Variable.Name, initExpr).WithILVariable(inst.Variable)); fixedStmt.EmbeddedStatement = Convert(inst.Body);