From 79b0cbb719701ae507eaae53f2dd1b017e1cc8be Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Tue, 7 Apr 2026 23:31:58 +0200 Subject: [PATCH] Fix #3703: Do not transform to a primary constructor if it's not public (or protected in abstract classes) --- .../TestCases/Pretty/ConstructorInitializers.cs | 12 +++++++++++- ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs | 3 +++ .../TransformFieldAndConstructorInitializers.cs | 5 ++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs index d139c6d5e..7f671a7eb 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs @@ -134,7 +134,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public MethodCallInCtorInit(ConsoleKey key) #if MCS5 - : this(((int)key/*cast due to .constrained prefix*/).ToString()) + : this(((int)key/*cast due to constrained. prefix*/).ToString()) #else : this(((int)key).ToString()) #endif @@ -286,6 +286,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } #endif + + public struct My + { + private ClassWithConstantAndStaticCtor test; + + internal My(ClassWithConstantAndStaticCtor a) + { + test = a; + } + } #endif } } diff --git a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs index 1896b34e7..84a80cc18 100644 --- a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs @@ -179,12 +179,15 @@ namespace ICSharpCode.Decompiler.CSharp } IMethod? guessedPrimaryCtor = null; + Accessibility expectedCtorAccessibility = recordTypeDef.IsAbstract ? Accessibility.Protected : Accessibility.Public; foreach (var method in recordTypeDef.Methods) { cancellationToken.ThrowIfCancellationRequested(); if (method.IsStatic || !method.IsConstructor) continue; + if (method.Accessibility != expectedCtorAccessibility) + continue; if (IsCopyConstructor(method)) { continue; diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs index 3a0e19769..2bc98bbcf 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs @@ -340,6 +340,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } } + Accessibility expectedCtorAccessibility = TypeDefinition.IsAbstract ? Accessibility.Protected : Accessibility.Public; + if (context.Settings.UsePrimaryConstructorSyntaxForNonRecordTypes && RecordDecompiler == null && constructorsNotChainedWithThis.Count == 1) { @@ -351,7 +353,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms var initializer = InitializerSequence.Analyze(this, ctor, ctorMethod); - if (initializer is { CoversFullBody: true, HasDuplicateAssignments: false, Statements.Count: > 0 }) + if (initializer is { CoversFullBody: true, HasDuplicateAssignments: false, Statements.Count: > 0 } + && ctorMethod.Accessibility == expectedCtorAccessibility) { bool transformToPrimaryConstructor = MetadataTokens.GetRowNumber(ctorMethod.MetadataToken) == firstMethodRowNumber;