diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs index eebe03476..31837e1ec 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs @@ -69,6 +69,31 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + // Multiple constructors that do not chain with this and assign fields differently must not + // prevent the remaining constructor's this(...) chain from being lifted to an initializer. + public struct StructWithDivergentCtorsAndThisChain + { + public int X; + public int Y; + + public StructWithDivergentCtorsAndThisChain(int x, int y) + { + X = x; + Y = y; + } + + public StructWithDivergentCtorsAndThisChain(int x) + { + X = x; + Y = 0; + } + + public StructWithDivergentCtorsAndThisChain(string s) + : this(s.Length) + { + } + } + #if CS120 public struct Issue1743WithPrimaryCtor(int dummy1, int dummy2) { diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs index d817decd3..63da3e010 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs @@ -430,13 +430,27 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (sequence == null) return false; + bool sequenceMatchesAllCtors = true; for (int i = 1; i < constructorsNotChainedWithThis.Count; i++) { if (!sequence.IsMatch(constructorsNotChainedWithThis[i])) - return false; + { + sequenceMatchesAllCtors = false; + break; + } } - if (!isPrimaryCtor) + if (!sequenceMatchesAllCtors) + { + // The non-this-chained constructors disagree on their leading field + // assignments, so there is no shared field-initializer sequence to extract. + // A primary constructor must extract its initializers (its parameters drive + // them), so bail; otherwise keep the assignments in the bodies but continue, + // so the this(...)/base(...) chains still get lifted to initializers. + if (isPrimaryCtor) + return false; + } + else if (!isPrimaryCtor) { if (!sequence.Statements.Any(s => s.DependsOnConstructorBody)) InstanceInitializers = sequence;