Browse Source

Fix #1743: Add pattern for struct constructor initializers.

pull/1746/head
Siegfried Pammer 6 years ago
parent
commit
b1352aa569
  1. 16
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs
  2. 71
      ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs

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

@ -20,6 +20,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -20,6 +20,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class ConstructorInitializers
{
public struct Issue1743
{
public int Leet;
public Issue1743(int dummy)
: this(dummy, dummy)
{
Leet += dummy;
}
public Issue1743(int dummy1, int dummy2)
{
Leet = dummy1 + dummy2;
}
}
public struct SimpleStruct
{
public int Field1;

71
ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -58,30 +58,55 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -58,30 +58,55 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
var stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (stmt == null)
if (!(constructorDeclaration.Body.Statements.FirstOrDefault() is ExpressionStatement stmt))
return;
if (!(stmt.Expression is InvocationExpression invocation))
return;
if (invocation.Target is MemberReferenceExpression mre && mre.MemberName == ".ctor") {
ConstructorInitializer ci = new ConstructorInitializer();
var target = mre.Target;
// Ignore casts, those might be added if references are missing.
if (target is CastExpression cast)
target = cast.Expression;
if (target is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else if (target is BaseReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.Base;
else
return;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement:
stmt.Remove();
var currentCtor = (IMethod)constructorDeclaration.GetSymbol();
ConstructorInitializer ci;
switch (stmt.Expression) {
// Pattern for reference types:
// this..ctor(...);
case InvocationExpression invocation:
if (!(invocation.Target is MemberReferenceExpression mre) || mre.MemberName != ".ctor")
return;
if (!(invocation.GetSymbol() is IMethod ctor && ctor.IsConstructor))
return;
ci = new ConstructorInitializer();
var target = mre.Target;
// Ignore casts, those might be added if references are missing.
if (target is CastExpression cast)
target = cast.Expression;
if (target is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else if (target is BaseReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.Base;
else
return;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement:
stmt.Remove();
break;
// Pattern for value types:
// this = new TSelf(...);
case AssignmentExpression assignment:
if (!(assignment.Right is ObjectCreateExpression oce && oce.GetSymbol() is IMethod ctor2 && ctor2.DeclaringTypeDefinition == currentCtor.DeclaringTypeDefinition))
return;
ci = new ConstructorInitializer();
if (assignment.Left is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else
return;
// Move arguments from invocation to initializer:
oce.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(oce);
// Remove the statement:
stmt.Remove();
break;
}
}

Loading…
Cancel
Save