Browse Source

Keep instance-dependent assignments in constructors

A moved field initializer cannot read another instance member. Reject primary-constructor conversion for that case and preserve the original constructor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0dd407b6-9410-48df-add5-761ca4a8dec0
pull/3980/head
Sebastien Lebreton 1 month ago committed by Siegfried Pammer
parent
commit
2d2e9c15ef
  1. 13
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs
  2. 19
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

13
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs

@ -134,6 +134,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -134,6 +134,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public int B = b;
}
private struct StructInitializerDependsOnField
{
public int A;
public int B;
public StructInitializerDependsOnField(int value)
{
A = value;
B = A + 1;
}
}
#endif
public class ClassWithConstant

19
ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

@ -356,6 +356,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -356,6 +356,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var initializer = InitializerSequence.Analyze(this, ctor, ctorMethod);
if (initializer is { CoversFullBody: true, HasDuplicateAssignments: false, Statements.Count: > 0 }
&& !initializer.Statements.Any(statement => ReferencesInstanceMember(statement.Initializer))
&& ctorMethod.Accessibility == expectedCtorAccessibility)
{
bool transformToPrimaryConstructor = MetadataTokens.GetRowNumber(ctorMethod.MetadataToken) == firstMethodRowNumber;
@ -403,6 +404,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -403,6 +404,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
bool ReferencesInstanceMember(Expression expression)
{
foreach (var node in expression.DescendantsAndSelf.OfType<Expression>())
{
switch (node.GetResolveResult())
{
case ThisResolveResult:
return true;
case MemberResolveResult {
TargetResult: ThisResolveResult,
Member: { IsStatic: false } member
} when member is not IField field || !IsGeneratedPrimaryConstructorBackingField(field):
return true;
}
}
return false;
}
if (StaticConstructor != null)
{
StaticInitializers = InitializerSequence.Analyze(this, StaticConstructorDecl!, StaticConstructor);

Loading…
Cancel
Save