Browse Source

Fix #3392: uses of init-setters must use object-initializer syntax.

pull/3403/head
Siegfried Pammer 6 months ago
parent
commit
906d248403
  1. 24
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  2. 8
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

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

@ -235,6 +235,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
{ {
int Property { get; set; } int Property { get; set; }
} }
#if CS90
public class Issue3392Type
{
public bool Flag { get; init; }
public List<int> List { get; } = new List<int>();
public Issue3392Type(object x)
{
}
}
#endif
#endregion #endregion
private S s1; private S s1;
@ -1010,6 +1023,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
otherItem.Data2.Nullable = 3m; otherItem.Data2.Nullable = 3m;
return otherItem; return otherItem;
} }
#if CS90
public Issue3392Type Issue3392(Issue3392Type x)
{
x = new Issue3392Type(null) {
Flag = false
};
x.List.AddRange(Enumerable.Range(0, 10));
return x;
}
#endif
#if CS60 #if CS60
public OtherItem2 Issue1345c() public OtherItem2 Issue1345c()
{ {

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

@ -103,6 +103,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; return;
} }
int initializerItemsCount = 0; int initializerItemsCount = 0;
bool initializerContainsInitOnlyItems = false;
possibleIndexVariables.Clear(); possibleIndexVariables.Clear();
currentPath.Clear(); currentPath.Clear();
isCollection = false; isCollection = false;
@ -113,13 +114,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if the method is a setter we're dealing with an object initializer // if the method is a setter we're dealing with an object initializer
// if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer // if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer
while (pos + initializerItemsCount + 1 < block.Instructions.Count while (pos + initializerItemsCount + 1 < block.Instructions.Count
&& IsPartOfInitializer(block.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockKind, context)) && IsPartOfInitializer(block.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockKind, ref initializerContainsInitOnlyItems, context))
{ {
initializerItemsCount++; initializerItemsCount++;
} }
// Do not convert the statements into an initializer if there's an incompatible usage of the initializer variable // Do not convert the statements into an initializer if there's an incompatible usage of the initializer variable
// directly after the possible initializer. // directly after the possible initializer.
if (IsMethodCallOnVariable(block.Instructions[pos + initializerItemsCount + 1], v)) if (!initializerContainsInitOnlyItems && IsMethodCallOnVariable(block.Instructions[pos + initializerItemsCount + 1], v))
return; return;
// Calculate the correct number of statements inside the initializer: // Calculate the correct number of statements inside the initializer:
// All index variables that were used in the initializer have Index set to -1. // All index variables that were used in the initializer have Index set to -1.
@ -200,7 +201,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool isCollection; bool isCollection;
readonly Stack<HashSet<AccessPathElement>> pathStack = new Stack<HashSet<AccessPathElement>>(); readonly Stack<HashSet<AccessPathElement>> pathStack = new Stack<HashSet<AccessPathElement>>();
bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockKind blockKind, StatementTransformContext context) bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockKind blockKind, ref bool initializerContainsInitOnlyItems, StatementTransformContext context)
{ {
// Include any stores to local variables that are single-assigned and do not reference the initializer-variable // Include any stores to local variables that are single-assigned and do not reference the initializer-variable
// in the list of possible index variables. // in the list of possible index variables.
@ -255,6 +256,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (blockKind != BlockKind.ObjectInitializer && blockKind != BlockKind.WithInitializer) if (blockKind != BlockKind.ObjectInitializer && blockKind != BlockKind.WithInitializer)
blockKind = BlockKind.ObjectInitializer; blockKind = BlockKind.ObjectInitializer;
initializerContainsInitOnlyItems |= lastElement.Member is IProperty { Setter.IsInitOnly: true };
return true; return true;
default: default:
return false; return false;

Loading…
Cancel
Save