From 2a0675fb4a9672f991efbd330df1c4197bc29d17 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 5 May 2025 12:47:03 -0700 Subject: [PATCH] Handle explicit optional parameter after default parameter --- .../TestCases/Pretty/OptionalArguments.cs | 4 +++ .../CSharp/Syntax/TypeSystemAstBuilder.cs | 3 +- .../TypeSystem/IParameter.cs | 30 +++++++++++++++++++ .../Implementation/MetadataParameter.cs | 6 ++-- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs index d69c8f35a..f76f75183 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.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; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -307,6 +308,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { } #endif + public static void Issue3469([Optional][DefaultParameterValue(0)] int i, [Optional] DateTime d) + { + } #if CS120 public static D LambdaWithOptionalParameter() diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 3583c6a44..b95655ba5 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -1735,8 +1735,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { decl.Name = parameter.Name; } - if (parameter.IsOptional && decl.ParameterModifier is ReferenceKind.None or ReferenceKind.In or ReferenceKind.RefReadOnly - && parameter.HasConstantValueInSignature && this.ShowConstantValues) + if (parameter.GetDefaultValueAssignmentAllowed() && this.ShowConstantValues) { try { diff --git a/ICSharpCode.Decompiler/TypeSystem/IParameter.cs b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs index 481613318..923ec06e3 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs @@ -105,4 +105,34 @@ namespace ICSharpCode.Decompiler.TypeSystem /// IParameterizedMember? Owner { get; } } + + internal static class IParameterExtensions + { + public static bool GetDefaultValueAssignmentAllowed(this IParameter parameter) + { + if (!DefaultValueAssignmentAllowedIndividual(parameter)) + return false; + + if (parameter.Owner == null) + return true; + + for (int i = parameter.Owner.Parameters.Count - 1; i >= 0; i--) + { + IParameter otherParameter = parameter.Owner.Parameters[i]; + if (otherParameter == parameter) + break; + + if (DefaultValueAssignmentAllowedIndividual(otherParameter) || otherParameter.IsParams) + continue; + + return false; + } + return true; + + static bool DefaultValueAssignmentAllowedIndividual(IParameter parameter) + { + return parameter.IsOptional && parameter.HasConstantValueInSignature && parameter.ReferenceKind is ReferenceKind.None or ReferenceKind.In or ReferenceKind.RefReadOnly; + } + } + } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs index 14bee08dc..3067f135e 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs @@ -63,14 +63,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var metadata = module.metadata; var parameter = metadata.GetParameter(handle); - bool defaultValueAssignmentAllowed = ReferenceKind is ReferenceKind.None or ReferenceKind.In or ReferenceKind.RefReadOnly; + bool defaultValueAssignmentAllowed = this.GetDefaultValueAssignmentAllowed(); - if (IsOptional && (!defaultValueAssignmentAllowed || !HasConstantValueInSignature)) + if (IsOptional && !defaultValueAssignmentAllowed) { b.Add(KnownAttribute.Optional); } - if (!(IsDecimalConstant || !HasConstantValueInSignature) && (!defaultValueAssignmentAllowed || !IsOptional)) + if (!IsDecimalConstant && HasConstantValueInSignature && !defaultValueAssignmentAllowed) { b.Add(KnownAttribute.DefaultParameterValue, KnownTypeCode.Object, GetConstantValue(throwOnInvalidMetadata: false)); }