Browse Source

#2390: Add support for generic object initializers.

pull/2408/head
Siegfried Pammer 4 years ago
parent
commit
d54016ce8f
  1. 12
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  2. 7
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 10
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  4. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

12
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

@ -226,6 +226,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -226,6 +226,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
public Item I;
}
#endif
public interface IData
{
int Property { get; set; }
}
#endregion
#region Field initializer tests
@ -1036,6 +1041,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -1036,6 +1041,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
}
}
#endif
private TData GenericObjectInitializer<TData>() where TData : IData, new()
{
return new TData {
Property = 42
};
}
#endregion
#region Collection initializer

7
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3161,6 +3161,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3161,6 +3161,13 @@ namespace ICSharpCode.Decompiler.CSharp
expr = TranslateCallWithNamedArgs(callWithNamedArgs);
initObjRR = new InitializedObjectResolveResult(expr.Type);
break;
case Call c when c.Method.FullNameIs("System.Activator", "CreateInstance") && c.Method.TypeArguments.Count == 1:
IType type = c.Method.TypeArguments[0];
initObjRR = new InitializedObjectResolveResult(type);
expr = new ObjectCreateExpression(ConvertType(type))
.WithILInstruction(c)
.WithRR(new TypeResolveResult(type));
break;
default:
throw new ArgumentException("given Block is invalid!");
}

10
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -151,6 +151,7 @@ namespace ICSharpCode.Decompiler.IL @@ -151,6 +151,7 @@ namespace ICSharpCode.Decompiler.IL
break;
case BlockKind.CollectionInitializer:
case BlockKind.ObjectInitializer:
case BlockKind.WithInitializer:
var final2 = finalInstruction as LdLoc;
Debug.Assert(final2 != null);
var initVar2 = final2.Variable;
@ -161,6 +162,7 @@ namespace ICSharpCode.Decompiler.IL @@ -161,6 +162,7 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(init2 is NewObj
|| init2 is DefaultValue
|| (init2 is CallInstruction ci && TransformCollectionAndObjectInitializers.IsRecordCloneMethodCall(ci))
|| (init2 is CallInstruction c && c.Method.FullNameIs("System.Activator", "CreateInstance") && c.Method.TypeArguments.Count == 1)
|| (init2 is Block named && named.Kind == BlockKind.CallWithNamedArgs));
switch (init2)
{
@ -173,13 +175,19 @@ namespace ICSharpCode.Decompiler.IL @@ -173,13 +175,19 @@ namespace ICSharpCode.Decompiler.IL
case Block callWithNamedArgs when callWithNamedArgs.Kind == BlockKind.CallWithNamedArgs:
type2 = ((CallInstruction)callWithNamedArgs.FinalInstruction).Method.ReturnType;
break;
case CallInstruction ci2 when TransformCollectionAndObjectInitializers.IsRecordCloneMethodCall(ci2):
type2 = ci2.Method.DeclaringType;
break;
case Call c2 when c2.Method.FullNameIs("System.Activator", "CreateInstance") && c2.Method.TypeArguments.Count == 1:
type2 = c2.Method.TypeArguments[0];
break;
default:
Debug.Assert(false);
break;
}
for (int i = 1; i < Instructions.Count; i++)
{
Debug.Assert(Instructions[i] is StLoc || AccessPathElement.GetAccessPath(Instructions[i], type2).Kind != IL.Transforms.AccessPathKind.Invalid);
Debug.Assert(Instructions[i] is StLoc || AccessPathElement.GetAccessPath(Instructions[i], type2).Kind != AccessPathKind.Invalid);
}
break;
case BlockKind.DeconstructionConversions:

4
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -95,6 +95,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -95,6 +95,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
instType = defaultVal.Type;
break;
case Call c when c.Method.FullNameIs("System.Activator", "CreateInstance") && c.Method.TypeArguments.Count == 1:
instType = c.Method.TypeArguments[0];
blockKind = BlockKind.ObjectInitializer;
break;
case CallInstruction ci when context.Settings.WithExpressions && IsRecordCloneMethodCall(ci):
instType = ci.Method.DeclaringType;
blockKind = BlockKind.WithInitializer;

Loading…
Cancel
Save