Browse Source

Implement Block.CheckInvariant for BlockKind.ArrayInitializer, BlockKind.CollectionInitializer and BlockKind.ObjectInitializer

pull/2005/head
Siegfried Pammer 5 years ago
parent
commit
6042819117
  1. 37
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  2. 6
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

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

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
@ -131,6 +132,42 @@ namespace ICSharpCode.Decompiler.IL @@ -131,6 +132,42 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(call.Arguments[0].MatchLdLoc(v));
}
break;
case BlockKind.ArrayInitializer:
var final = finalInstruction as LdLoc;
Debug.Assert(final != null && final.Variable.Kind == VariableKind.InitializerTarget);
IType type = null;
Debug.Assert(Instructions[0].MatchStLoc(final.Variable, out var init) && init.MatchNewArr(out type));
for (int i = 1; i < Instructions.Count; i++) {
Debug.Assert(Instructions[i].MatchStObj(out ILInstruction target, out ILInstruction value, out var t) && type != null && type.Equals(t));
Debug.Assert(target.MatchLdElema(out t, out ILInstruction array) && type.Equals(t));
Debug.Assert(array.MatchLdLoc(out ILVariable v) && v == final.Variable);
}
break;
case BlockKind.CollectionInitializer:
case BlockKind.ObjectInitializer:
var final2 = finalInstruction as LdLoc;
Debug.Assert(final2 != null && final2.Variable.Kind == VariableKind.InitializerTarget);
IType type2 = null;
Debug.Assert(Instructions[0].MatchStLoc(final2.Variable, out var init2));
Debug.Assert(init2 is NewObj || init2 is DefaultValue || (init2 is Block named && named.Kind == BlockKind.CallWithNamedArgs));
switch (init2) {
case NewObj newObj:
type2 = newObj.Method.DeclaringType;
break;
case DefaultValue defaultValue:
type2 = defaultValue.Type;
break;
case Block callWithNamedArgs when callWithNamedArgs.Kind == BlockKind.CallWithNamedArgs:
type2 = ((CallInstruction)callWithNamedArgs.FinalInstruction).Method.ReturnType;
break;
default:
Debug.Assert(false);
break;
}
for (int i = 1; i < Instructions.Count; i++) {
Debug.Assert(Instructions[i] is StLoc || IL.Transforms.AccessPathElement.GetAccessPath(Instructions[i], type2).Kind != IL.Transforms.AccessPathKind.Invalid);
}
break;
}
}

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

@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public override string ToString() => $"[{Member}, {Indices}]";
public static (AccessPathKind Kind, List<AccessPathElement> Path, List<ILInstruction> Values, ILVariable Target) GetAccessPath(
ILInstruction instruction, IType rootType, DecompilerSettings settings,
ILInstruction instruction, IType rootType, DecompilerSettings settings = null,
CSharpTypeResolveContext resolveContext = null,
Dictionary<ILVariable, (int Index, ILInstruction Value)> possibleIndexVariables = null)
{
@ -282,7 +282,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -282,7 +282,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!CanBeUsedInInitializer(property, resolveContext, kind, path)) goto default;
var isGetter = method.Equals(property?.Getter);
var indices = call.Arguments.Skip(1).Take(call.Arguments.Count - (isGetter ? 1 : 2)).ToArray();
if (indices.Length > 0 && !settings.DictionaryInitializers) goto default;
if (indices.Length > 0 && settings?.DictionaryInitializers == false) goto default;
if (possibleIndexVariables != null) {
// Mark all index variables as used
foreach (var index in indices.OfType<IInstructionWithVariableOperand>()) {
@ -373,7 +373,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -373,7 +373,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!"Add".Equals(method.Name, StringComparison.Ordinal) || arguments.Count == 0)
return false;
if (method.IsExtensionMethod)
return settings.ExtensionMethodsInCollectionInitializers
return settings?.ExtensionMethodsInCollectionInitializers != false
&& CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(method, resolveContext, ignoreTypeArguments: true);
var targetType = GetReturnTypeFromInstruction(arguments[0]) ?? rootType;
if (targetType == null)

Loading…
Cancel
Save