Browse Source

Fix #3671: TransformCollectionAndObjectInitializers mistakenly included trailing variable initialization.

pull/3691/head
Siegfried Pammer 2 weeks ago
parent
commit
fae6f57b1c
  1. 20
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  2. 33
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

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

@ -185,7 +185,25 @@ namespace ICSharpCode.Decompiler.IL @@ -185,7 +185,25 @@ namespace ICSharpCode.Decompiler.IL
}
for (int i = 1; i < Instructions.Count; i++)
{
Debug.Assert(Instructions[i] is StLoc || AccessPathElement.GetAccessPath(Instructions[i], type2).Kind != AccessPathKind.Invalid);
if (Instructions[i] is StLoc { Variable: var v })
{
foreach (var inst in v.LoadInstructions)
{
Debug.Assert(inst.IsDescendantOf(this));
}
foreach (var inst in v.AddressInstructions)
{
Debug.Assert(inst.IsDescendantOf(this));
}
foreach (ILInstruction inst in v.StoreInstructions)
{
Debug.Assert(inst.IsDescendantOf(this));
}
}
else
{
Debug.Assert(AccessPathElement.GetAccessPath(Instructions[i], type2).Kind != AccessPathKind.Invalid);
}
}
break;
case BlockKind.DeconstructionConversions:

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

@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
possibleIndexVariables.Add(stloc.Variable, (stloc.ChildIndex, stloc.Value));
return true;
}
(var kind, var newPath, var values, var targetVariable) = AccessPathElement.GetAccessPath(instructions[pos], rootType, context.Settings, context.CSharpResolver, possibleIndexVariables);
(var kind, var newPath, var values, var targetVariable, var usedIndices) = AccessPathElement.GetAccessPath(instructions[pos], rootType, context.Settings, context.CSharpResolver);
if (kind == AccessPathKind.Invalid || target != targetVariable)
return false;
// Treat last element separately:
@ -274,6 +274,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -274,6 +274,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
isCollection = true;
if (pathStack.Peek().Count != 0)
return false;
MarkUsedIndices();
return true;
case AccessPathKind.Setter:
if (isCollection || !pathStack.Peek().Add(lastElement))
@ -283,10 +284,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -283,10 +284,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (blockKind != BlockKind.ObjectInitializer && blockKind != BlockKind.WithInitializer)
blockKind = BlockKind.ObjectInitializer;
initializerContainsInitOnlyItems |= lastElement.Member is IProperty { Setter.IsInitOnly: true };
MarkUsedIndices();
return true;
default:
return false;
}
void MarkUsedIndices()
{
foreach (var index in usedIndices)
{
if (possibleIndexVariables.TryGetValue(index, out var item))
{
possibleIndexVariables[index] = (-1, item.Value);
}
}
}
}
bool IsValidObjectInitializerTarget(List<AccessPathElement> path)
@ -330,10 +343,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -330,10 +343,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public override string ToString() => $"[{Member}, {Indices}]";
public static (AccessPathKind Kind, List<AccessPathElement> Path, List<ILInstruction>? Values, ILVariable? Target) GetAccessPath(
public static (AccessPathKind Kind, List<AccessPathElement> Path, List<ILInstruction>? Values, ILVariable? Target, List<ILVariable> UsedIndexVariables) GetAccessPath(
ILInstruction instruction, IType rootType, DecompilerSettings? settings = null,
CSharpResolver? resolver = null,
Dictionary<ILVariable, (int Index, ILInstruction Value)>? possibleIndexVariables = null)
CSharpResolver? resolver = null)
{
List<AccessPathElement> path = new List<AccessPathElement>();
ILVariable? target = null;
@ -341,6 +353,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -341,6 +353,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
List<ILInstruction>? values = null;
IMethod method;
ILInstruction? inst = instruction;
List<ILVariable> usedIndexVariables = new();
while (inst != null)
{
switch (inst)
@ -368,14 +381,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -368,14 +381,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var indices = call.Arguments.Skip(1).Take(call.Arguments.Count - (isGetter ? 1 : 2)).ToArray();
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>())
{
// Mark all index variables as used
foreach (var index in indices.OfType<IInstructionWithVariableOperand>())
{
if (possibleIndexVariables.TryGetValue(index.Variable, out var info))
possibleIndexVariables[index.Variable] = (-1, info.Value);
}
usedIndexVariables.Add(index.Variable);
}
path.Insert(0, new AccessPathElement(call.OpCode, method.AccessorOwner, indices));
}
@ -460,7 +469,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -460,7 +469,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (kind != AccessPathKind.Invalid && values != null && values.SelectMany(v => v.Descendants).OfType<IInstructionWithVariableOperand>().Any(ld => ld.Variable == target && (ld is LdLoc || ld is LdLoca)))
kind = AccessPathKind.Invalid;
return (kind, path, values, target);
return (kind, path, values, target, usedIndexVariables);
}
private static bool CanBeUsedInInitializer(IProperty property, ITypeResolveContext? resolveContext, AccessPathKind kind)

Loading…
Cancel
Save