diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 4af2803c0..50dc56748 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -71,6 +71,8 @@ + + diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs index ce61445ed..16fadeecf 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs @@ -42,6 +42,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Test(); Test(5); Test(10, "Hello World!"); + + Decimal(); + Decimal(5m); } private void Conflicts() @@ -124,6 +127,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { } + private void Decimal(decimal d = 10m) + { + } + private void OnlyDifferenceIsLastArgument(int a, int b, string c = null) { } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.il index 5a6e1b7af..cc01fe3db 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.il @@ -76,8 +76,8 @@ .method private hidebysig instance void SimpleTests() cil managed { - // Code size 43 (0x2b) - .maxstack 8 + // Code size 70 (0x46) + .maxstack 3 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.s 10 @@ -97,7 +97,17 @@ IL_0024: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Test(int32, string) IL_0029: nop - IL_002a: ret + IL_002a: ldarg.0 + IL_002b: ldc.i4.s 10 + IL_002d: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_0032: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0037: nop + IL_0038: ldarg.0 + IL_0039: ldc.i4.5 + IL_003a: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_003f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0044: nop + IL_0045: ret } // end of method OptionalArguments::SimpleTests .method private hidebysig instance void @@ -400,6 +410,22 @@ IL_0001: ret } // end of method OptionalArguments::Test + .method private hidebysig instance void + Decimal([opt] valuetype [mscorlib]System.Decimal d) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method OptionalArguments::Decimal + .method private hidebysig instance void OnlyDifferenceIsLastArgument(int32 a, int32 b, diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.il index d15e2c21a..e34d0deb9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.il @@ -69,8 +69,8 @@ .method private hidebysig instance void SimpleTests() cil managed { - // Code size 39 (0x27) - .maxstack 8 + // Code size 64 (0x40) + .maxstack 3 IL_0000: ldarg.0 IL_0001: ldc.i4.s 10 IL_0003: ldstr "Test" @@ -86,7 +86,15 @@ IL_001c: ldstr "Hello World!" IL_0021: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Test(int32, string) - IL_0026: ret + IL_0026: ldarg.0 + IL_0027: ldc.i4.s 10 + IL_0029: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_002e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0033: ldarg.0 + IL_0034: ldc.i4.5 + IL_0035: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_003a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_003f: ret } // end of method OptionalArguments::SimpleTests .method private hidebysig instance void @@ -358,6 +366,21 @@ IL_0000: ret } // end of method OptionalArguments::Test + .method private hidebysig instance void + Decimal([opt] valuetype [mscorlib]System.Decimal d) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method OptionalArguments::Decimal + .method private hidebysig instance void OnlyDifferenceIsLastArgument(int32 a, int32 b, diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.roslyn.il index c30b296a7..179bc8bff 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.opt.roslyn.il @@ -73,8 +73,8 @@ .method private hidebysig instance void SimpleTests() cil managed { - // Code size 39 (0x27) - .maxstack 8 + // Code size 64 (0x40) + .maxstack 3 IL_0000: ldarg.0 IL_0001: ldc.i4.s 10 IL_0003: ldstr "Test" @@ -90,7 +90,15 @@ IL_001c: ldstr "Hello World!" IL_0021: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Test(int32, string) - IL_0026: ret + IL_0026: ldarg.0 + IL_0027: ldc.i4.s 10 + IL_0029: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_002e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0033: ldarg.0 + IL_0034: ldc.i4.5 + IL_0035: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_003a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_003f: ret } // end of method OptionalArguments::SimpleTests .method private hidebysig instance void @@ -334,6 +342,21 @@ IL_0000: ret } // end of method OptionalArguments::Test + .method private hidebysig instance void + Decimal([opt] valuetype [mscorlib]System.Decimal d) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method OptionalArguments::Decimal + .method private hidebysig instance void OnlyDifferenceIsLastArgument(int32 a, int32 b, @@ -400,15 +423,15 @@ .size 12 } // end of class '__StaticArrayInitTypeSize=12' - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' '0F3DD643C5167ACFC541F72809FFF828A6E41494' at I_00002D2C - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' E429CCA3F703A39CC5954A6572FEC9086135B34E at I_00002D3C + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' '0F3DD643C5167ACFC541F72809FFF828A6E41494' at I_00002DC4 + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' E429CCA3F703A39CC5954A6572FEC9086135B34E at I_00002DD4 } // end of class '' // ============================================================= -.data cil I_00002D2C = bytearray ( +.data cil I_00002DC4 = bytearray ( 0A 00 00 00 09 00 00 00 08 00 00 00) -.data cil I_00002D3C = bytearray ( +.data cil I_00002DD4 = bytearray ( 01 00 00 00 02 00 00 00 03 00 00 00) // *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.roslyn.il index ea483f7eb..f8f4f8145 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.roslyn.il @@ -78,8 +78,8 @@ .method private hidebysig instance void SimpleTests() cil managed { - // Code size 43 (0x2b) - .maxstack 8 + // Code size 70 (0x46) + .maxstack 3 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.s 10 @@ -99,7 +99,17 @@ IL_0024: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Test(int32, string) IL_0029: nop - IL_002a: ret + IL_002a: ldarg.0 + IL_002b: ldc.i4.s 10 + IL_002d: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_0032: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0037: nop + IL_0038: ldarg.0 + IL_0039: ldc.i4.5 + IL_003a: newobj instance void [mscorlib]System.Decimal::.ctor(int32) + IL_003f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.OptionalArguments::Decimal(valuetype [mscorlib]System.Decimal) + IL_0044: nop + IL_0045: ret } // end of method OptionalArguments::SimpleTests .method private hidebysig instance void @@ -375,6 +385,22 @@ IL_0001: ret } // end of method OptionalArguments::Test + .method private hidebysig instance void + Decimal([opt] valuetype [mscorlib]System.Decimal d) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method OptionalArguments::Decimal + .method private hidebysig instance void OnlyDifferenceIsLastArgument(int32 a, int32 b, @@ -446,16 +472,15 @@ .size 12 } // end of class '__StaticArrayInitTypeSize=12' - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' '0F3DD643C5167ACFC541F72809FFF828A6E41494' at I_00002D58 - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' E429CCA3F703A39CC5954A6572FEC9086135B34E at I_00002D68 + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' '0F3DD643C5167ACFC541F72809FFF828A6E41494' at I_00002DF4 + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=12' E429CCA3F703A39CC5954A6572FEC9086135B34E at I_00002E04 } // end of class '' // ============================================================= -.data cil I_00002D58 = bytearray ( +.data cil I_00002DF4 = bytearray ( 0A 00 00 00 09 00 00 00 08 00 00 00) -.data cil I_00002D64 = int8[4] -.data cil I_00002D68 = bytearray ( +.data cil I_00002E04 = bytearray ( 01 00 00 00 02 00 00 00 03 00 00 00) // *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.Expected.cs b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.Expected.cs new file mode 100644 index 000000000..50c053240 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.Expected.cs @@ -0,0 +1,14 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly +{ + public class NoDecimalConstants + { + [DecimalConstant(1, 0, 0u, 0u, 10u)] + private static readonly decimal constant = 1.0m; + private void MethodWithOptionalParameter([Optional] [DecimalConstant(1, 0, 0u, 0u, 10u)] decimal parameter) + { + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.cs b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.cs new file mode 100644 index 000000000..a18aea7a8 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.cs @@ -0,0 +1,31 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly +{ + public class NoDecimalConstants + { + private const decimal constant = 1.0m; + + private void MethodWithOptionalParameter(decimal parameter = 1.0m) + { + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.opt.roslyn.il new file mode 100644 index 000000000..6f97629f2 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.opt.roslyn.il @@ -0,0 +1,95 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly NoDecimalConstants +{ + .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 + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 ) + + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module NoDecimalConstants.dll +.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 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants + extends [mscorlib]System.Object +{ + .field private static initonly valuetype [mscorlib]System.Decimal constant + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + .method private hidebysig instance void + MethodWithOptionalParameter([opt] valuetype [mscorlib]System.Decimal parameter) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method NoDecimalConstants::MethodWithOptionalParameter + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method NoDecimalConstants::.ctor + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + // Code size 17 (0x11) + .maxstack 8 + IL_0000: ldc.i4.s 10 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.1 + IL_0006: newobj instance void [mscorlib]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) + IL_000b: stsfld valuetype [mscorlib]System.Decimal ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants::constant + IL_0010: ret + } // end of method NoDecimalConstants::.cctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.roslyn.il new file mode 100644 index 000000000..ea109cfe6 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoDecimalConstants.roslyn.il @@ -0,0 +1,97 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly NoDecimalConstants +{ + .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 + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) + + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module NoDecimalConstants.dll +.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 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants + extends [mscorlib]System.Object +{ + .field private static initonly valuetype [mscorlib]System.Decimal constant + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + .method private hidebysig instance void + MethodWithOptionalParameter([opt] valuetype [mscorlib]System.Decimal parameter) cil managed + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + uint32, + uint32, + uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 0A 00 00 00 + 00 00 ) + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method NoDecimalConstants::MethodWithOptionalParameter + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method NoDecimalConstants::.ctor + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + // Code size 17 (0x11) + .maxstack 8 + IL_0000: ldc.i4.s 10 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.1 + IL_0006: newobj instance void [mscorlib]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) + IL_000b: stsfld valuetype [mscorlib]System.Decimal ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants::constant + IL_0010: ret + } // end of method NoDecimalConstants::.cctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoDecimalConstants + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs index dd8945797..2469e2555 100644 --- a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs @@ -658,6 +658,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(4, p.ConstantValue); } @@ -670,6 +671,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsFalse(p.HasConstantValueInSignature); // explicit optional parameter appears in type system if it's read from C#, but not when read from IL //Assert.AreEqual(1, p.GetAttributes().Count()); } @@ -682,6 +684,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual((int)StringComparison.OrdinalIgnoreCase, p.ConstantValue); } @@ -694,6 +697,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); Assert.AreEqual(0, p.GetAttributes().Count()); Assert.IsNull(p.ConstantValue); } @@ -706,6 +710,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); Assert.AreEqual(1L, p.ConstantValue); Assert.AreEqual(typeof(long), p.ConstantValue.GetType()); } @@ -718,10 +723,24 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); Assert.AreEqual(1L, p.ConstantValue); Assert.AreEqual(typeof(long), p.ConstantValue.GetType()); } + [Test] + public void MethodWithOptionalDecimalParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalDecimalParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.IsTrue(p.HasConstantValueInSignature); + Assert.AreEqual(1M, p.ConstantValue); + Assert.AreEqual(typeof(decimal), p.ConstantValue.GetType()); + } + [Test] public void VarArgsMethod() { diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs index 4a0c50fe5..6c36c9128 100644 --- a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs @@ -162,6 +162,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem public void MethodWithOptionalNullableParameter(int? x = null) { } public void MethodWithOptionalLongParameter(long x = 1) { } public void MethodWithOptionalNullableLongParameter(long? x = 1) { } + public void MethodWithOptionalDecimalParameter(decimal x = 1) { } public void VarArgsMethod(__arglist) { } } diff --git a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs index b91485a02..30230bda5 100644 --- a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs @@ -75,6 +75,14 @@ namespace ICSharpCode.Decompiler.Tests }); } + [Test] + public void NoDecimalConstants([ValueSource("roslynOnlyOptions")] CSharpCompilerOptions cscOptions) + { + RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { + DecimalConstants = false + }); + } + void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CSharpCompilerOptions cscOptions = CSharpCompilerOptions.None, DecompilerSettings decompilerSettings = null) { Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CSharpCompilerOptions.Library, decompilerSettings); diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 8c99c6a33..54a6021dd 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -933,7 +933,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax if (this.ShowParameterNames) { decl.Name = parameter.Name; } - if (parameter.IsOptional && this.ShowConstantValues) { + if (parameter.IsOptional && parameter.HasConstantValueInSignature && this.ShowConstantValues) { decl.DefaultExpression = ConvertConstantValue(parameter.Type, parameter.ConstantValue); } return decl; diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs index 1d8ce6a56..4642290a0 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs @@ -50,6 +50,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms public void Run(AstNode rootNode, TransformContext context) { + if (!context.Settings.DecimalConstants) + return; rootNode.AcceptVisitor(this); } } diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 49a4de71d..ef08fa1ac 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -221,6 +221,21 @@ namespace ICSharpCode.Decompiler } } + bool decimalConstants = true; + + /// + /// Decompile [DecimalConstant(...)] as simple literal values. + /// + public bool DecimalConstants { + get { return decimalConstants; } + set { + if (decimalConstants != value) { + decimalConstants = value; + OnPropertyChanged(); + } + } + } + bool fixedBuffers = true; /// diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 9033f3bac..a284f6442 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -349,6 +349,7 @@ + diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index c944ef851..362fd07e5 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -71,11 +71,15 @@ namespace ICSharpCode.Decompiler.TypeSystem /// Also, some code in the decompiler expects to be able to compare type/member definitions by reference equality, /// and thus will fail with uncached type systems. /// - Uncached = 0x10, + Uncached = 16, + /// + /// If this option is active, [DecimalConstantAttribute] is removed and constant values are transformed into simple decimal literals. + /// + DecimalConstants = 32, /// /// Default settings: all features enabled. /// - Default = Dynamic | Tuple | ExtensionMethods + Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants } /// @@ -95,6 +99,8 @@ namespace ICSharpCode.Decompiler.TypeSystem typeSystemOptions |= TypeSystemOptions.Tuple; if (settings.ExtensionMethods) typeSystemOptions |= TypeSystemOptions.ExtensionMethods; + if (settings.DecimalConstants) + typeSystemOptions |= TypeSystemOptions.DecimalConstants; return typeSystemOptions; } diff --git a/ICSharpCode.Decompiler/TypeSystem/IParameter.cs b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs index 06d777f0f..553d8f029 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs @@ -16,6 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Runtime.CompilerServices; using System.Collections.Generic; namespace ICSharpCode.Decompiler.TypeSystem @@ -48,6 +49,22 @@ namespace ICSharpCode.Decompiler.TypeSystem /// bool IsOptional { get; } + /// + /// Gets whether this parameter has a constant value when presented in method signature. + /// + /// + /// This can only be true if the parameter is optional, and it's true for most + /// optional parameters. However it is possible to compile a parameter without a default value, + /// and some parameters handle their default values in an special way. + /// + /// For example, does not use normal constants, + /// so when is false + /// we expose DecimalConstantAttribute directly instead of a constant value. + /// + /// On the call sites, though, we can still use the value inferred from the attribute. + /// + bool HasConstantValueInSignature { get; } + /// /// Gets the owner of this parameter. /// May return null; for example when parameters belong to lambdas or anonymous methods. diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs index 055ef5cbc..5e53daafb 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs @@ -199,7 +199,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation case "ExtensionAttribute": return (options & TypeSystemOptions.ExtensionMethods) != 0; case "DecimalConstantAttribute": - return true; + return (options & TypeSystemOptions.DecimalConstants) != 0; default: return false; } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DecimalConstantHelper.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DecimalConstantHelper.cs new file mode 100644 index 000000000..b65fdb5ef --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DecimalConstantHelper.cs @@ -0,0 +1,72 @@ +// Copyright (c) 2018 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Reflection.Metadata; + +namespace ICSharpCode.Decompiler.TypeSystem.Implementation +{ + static class DecimalConstantHelper + { + public static bool AllowsDecimalConstants(MetadataModule module) + { + return ((module.TypeSystemOptions & TypeSystemOptions.DecimalConstants) == TypeSystemOptions.DecimalConstants); + } + + public static bool IsDecimalConstant(MetadataModule module, CustomAttributeHandleCollection attributeHandles) + { + return attributeHandles.HasKnownAttribute(module.metadata, KnownAttribute.DecimalConstant); + } + + public static object GetDecimalConstantValue(MetadataModule module, CustomAttributeHandleCollection attributeHandles) + { + var metadata = module.metadata; + foreach (var attributeHandle in attributeHandles) { + var attribute = metadata.GetCustomAttribute(attributeHandle); + if (attribute.IsKnownAttribute(metadata, KnownAttribute.DecimalConstant)) + return TryDecodeDecimalConstantAttribute(module, attribute); + } + return null; + } + + static decimal? TryDecodeDecimalConstantAttribute(MetadataModule module, System.Reflection.Metadata.CustomAttribute attribute) + { + var attrValue = attribute.DecodeValue(module.TypeProvider); + if (attrValue.FixedArguments.Length != 5) + return null; + // DecimalConstantAttribute has the arguments (byte scale, byte sign, uint hi, uint mid, uint low) or (byte scale, byte sign, int hi, int mid, int low) + // Both of these invoke the Decimal constructor (int lo, int mid, int hi, bool isNegative, byte scale) with explicit argument conversions if required. + if (!(attrValue.FixedArguments[0].Value is byte scale && attrValue.FixedArguments[1].Value is byte sign)) + return null; + unchecked { + if (attrValue.FixedArguments[2].Value is uint hi + && attrValue.FixedArguments[3].Value is uint mid + && attrValue.FixedArguments[4].Value is uint lo) { + return new decimal((int)lo, (int)mid, (int)hi, sign != 0, scale); + } + } + { + if (attrValue.FixedArguments[2].Value is int hi + && attrValue.FixedArguments[3].Value is int mid + && attrValue.FixedArguments[4].Value is int lo) { + return new decimal(lo, mid, hi, sign != 0, scale); + } + } + return null; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs index 28d0873d5..7642ad98c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs @@ -102,6 +102,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return false; } } + public bool HasConstantValueInSignature { + get { return IsOptional; } + } + public object ConstantValue { get { return defaultValue; } } @@ -123,7 +127,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation b.Append(parameter.Name); b.Append(':'); b.Append(parameter.Type.ReflectionName); - if (parameter.IsOptional) { + if (parameter.IsOptional && parameter.HasConstantValueInSignature) { b.Append(" = "); if (parameter.ConstantValue != null) b.Append(parameter.ConstantValue.ToString()); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs index cc3e9ac79..d345d472f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs @@ -78,6 +78,7 @@ namespace ICSharpCode.Decompiler.TypeSystem ParamArray, In, Out, + Optional, CallerMemberName, CallerFilePath, CallerLineNumber, @@ -133,6 +134,7 @@ namespace ICSharpCode.Decompiler.TypeSystem new TopLevelTypeName("System", nameof(ParamArrayAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(InAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(OutAttribute)), + new TopLevelTypeName("System.Runtime.InteropServices", nameof(OptionalAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CallerMemberNameAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CallerFilePathAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CallerLineNumberAttribute)), diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs index d7c942730..ac1aa6c3f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation object constantValue; IType type; bool isVolatile; // initialized together with this.type - byte decimalConstant; // 0=no, 1=yes, 2=unknown + bool? isDecimalConstant; internal MetadataField(MetadataModule module, FieldDefinitionHandle handle) { @@ -52,8 +52,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation this.handle = handle; var def = module.metadata.GetFieldDefinition(handle); this.attributes = def.Attributes; - if ((attributes & (FieldAttributes.Static | FieldAttributes.InitOnly)) == (FieldAttributes.Static | FieldAttributes.InitOnly)) { - decimalConstant = 2; // may be decimal constant + + if ((attributes & (FieldAttributes.Static | FieldAttributes.InitOnly)) != (FieldAttributes.Static | FieldAttributes.InitOnly)) { + isDecimalConstant = false; } } @@ -187,19 +188,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return LazyInit.GetOrSet(ref this.type, ty); } - public bool IsConst => (attributes & FieldAttributes.Literal) != 0 || IsDecimalConstant; + public bool IsConst => (attributes & FieldAttributes.Literal) != 0 + || (IsDecimalConstant && DecimalConstantHelper.AllowsDecimalConstants(module)); bool IsDecimalConstant { get { - if (decimalConstant == 2) { - var metadata = module.metadata; - var fieldDef = metadata.GetFieldDefinition(handle); - if (fieldDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.DecimalConstant)) - decimalConstant = 1; - else - decimalConstant = 0; + if (isDecimalConstant == null) { + var fieldDef = module.metadata.GetFieldDefinition(handle); + isDecimalConstant = DecimalConstantHelper.IsDecimalConstant(module, fieldDef.GetCustomAttributes()); } - return decimalConstant == 1; + return (bool)isDecimalConstant; } } @@ -210,13 +208,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return val; var metadata = module.metadata; var fieldDef = metadata.GetFieldDefinition(handle); - if (IsDecimalConstant) { - foreach (var attrHandle in fieldDef.GetCustomAttributes()) { - var attribute = metadata.GetCustomAttribute(attrHandle); - if (attribute.IsKnownAttribute(metadata, KnownAttribute.DecimalConstant)) { - val = TryDecodeDecimalConstantAttribute(attribute); - } - } + if (IsDecimalConstant && DecimalConstantHelper.AllowsDecimalConstants(module)) { + val = DecimalConstantHelper.GetDecimalConstantValue(module, fieldDef.GetCustomAttributes()); } else { var constantHandle = fieldDef.GetDefaultValue(); if (constantHandle.IsNil) @@ -229,32 +222,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } - decimal? TryDecodeDecimalConstantAttribute(System.Reflection.Metadata.CustomAttribute attribute) - { - var attrValue = attribute.DecodeValue(module.TypeProvider); - if (attrValue.FixedArguments.Length != 5) - return null; - // DecimalConstantAttribute has the arguments (byte scale, byte sign, uint hi, uint mid, uint low) or (byte scale, byte sign, int hi, int mid, int low) - // Both of these invoke the Decimal constructor (int lo, int mid, int hi, bool isNegative, byte scale) with explicit argument conversions if required. - if (!(attrValue.FixedArguments[0].Value is byte scale && attrValue.FixedArguments[1].Value is byte sign)) - return null; - unchecked { - if (attrValue.FixedArguments[2].Value is uint hi - && attrValue.FixedArguments[3].Value is uint mid - && attrValue.FixedArguments[4].Value is uint lo) { - return new decimal((int)lo, (int)mid, (int)hi, sign != 0, scale); - } - } - { - if (attrValue.FixedArguments[2].Value is int hi - && attrValue.FixedArguments[3].Value is int mid - && attrValue.FixedArguments[4].Value is int lo) { - return new decimal(lo, mid, hi, sign != 0, scale); - } - } - return null; - } - public override bool Equals(object obj) { if (obj is MetadataField f) { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs index 1dad96af7..426e238d0 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs @@ -37,6 +37,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation // lazy-loaded: string name; + bool? hasConstantValueInSignature; + bool? isDecimalConstant; internal MetadataParameter(MetadataModule module, IParameterizedMember owner, IType type, ParameterHandle handle) { @@ -47,6 +49,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var param = module.metadata.GetParameter(handle); this.attributes = param.Attributes; + if (!IsOptional) + isDecimalConstant = false; // only optional parameters can be constants } public EntityHandle MetadataToken => handle; @@ -58,6 +62,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var metadata = module.metadata; var parameter = metadata.GetParameter(handle); + if (IsOptional && !HasConstantValueInSignature) + b.Add(KnownAttribute.Optional); + if (!IsOut) { if ((attributes & ParameterAttributes.In) == ParameterAttributes.In) b.Add(KnownAttribute.In); @@ -102,16 +109,44 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public object ConstantValue { get { var metadata = module.metadata; - var propertyDef = metadata.GetParameter(handle); - var constantHandle = propertyDef.GetDefaultValue(); + var parameterDef = metadata.GetParameter(handle); + if (IsDecimalConstant) + return DecimalConstantHelper.GetDecimalConstantValue(module, parameterDef.GetCustomAttributes()); + + var constantHandle = parameterDef.GetDefaultValue(); if (constantHandle.IsNil) return null; + var constant = metadata.GetConstant(constantHandle); var blobReader = metadata.GetBlobReader(constant.Value); return blobReader.ReadConstant(constant.TypeCode); } } + public bool HasConstantValueInSignature { + get { + if (hasConstantValueInSignature == null) { + if (IsDecimalConstant) { + hasConstantValueInSignature = DecimalConstantHelper.AllowsDecimalConstants(module); + } + else { + hasConstantValueInSignature = !module.metadata.GetParameter(handle).GetDefaultValue().IsNil; + } + } + return (bool)hasConstantValueInSignature; + } + } + + bool IsDecimalConstant { + get { + if (isDecimalConstant == null) { + var parameterDef = module.metadata.GetParameter(handle); + isDecimalConstant = DecimalConstantHelper.IsDecimalConstant(module, parameterDef.GetCustomAttributes()); + } + return (bool)isDecimalConstant; + } + } + SymbolKind ISymbol.SymbolKind => SymbolKind.Parameter; public override string ToString() diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs index bca6f3075..bd34dbe92 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation bool IParameter.IsOut => baseParameter.IsOut; bool IParameter.IsParams => baseParameter.IsParams; bool IParameter.IsOptional => baseParameter.IsOptional; + bool IParameter.HasConstantValueInSignature => baseParameter.HasConstantValueInSignature; IParameterizedMember IParameter.Owner => newOwner; string IVariable.Name => baseParameter.Name; string ISymbol.Name => baseParameter.Name;