Skip to content

Commit 906d248

Browse files
Fix #3392: uses of init-setters must use object-initializer syntax.
1 parent fa50e8d commit 906d248

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ public interface IData
235235
{
236236
int Property { get; set; }
237237
}
238+
239+
#if CS90
240+
public class Issue3392Type
241+
{
242+
public bool Flag { get; init; }
243+
public List<int> List { get; } = new List<int>();
244+
245+
public Issue3392Type(object x)
246+
{
247+
248+
}
249+
}
250+
#endif
238251
#endregion
239252

240253
private S s1;
@@ -1010,6 +1023,17 @@ public OtherItem2 Issue1345b()
10101023
otherItem.Data2.Nullable = 3m;
10111024
return otherItem;
10121025
}
1026+
1027+
#if CS90
1028+
public Issue3392Type Issue3392(Issue3392Type x)
1029+
{
1030+
x = new Issue3392Type(null) {
1031+
Flag = false
1032+
};
1033+
x.List.AddRange(Enumerable.Range(0, 10));
1034+
return x;
1035+
}
1036+
#endif
10131037
#if CS60
10141038
public OtherItem2 Issue1345c()
10151039
{

ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ void IStatementTransform.Run(Block block, int pos, StatementTransformContext con
103103
return;
104104
}
105105
int initializerItemsCount = 0;
106+
bool initializerContainsInitOnlyItems = false;
106107
possibleIndexVariables.Clear();
107108
currentPath.Clear();
108109
isCollection = false;
@@ -113,13 +114,13 @@ void IStatementTransform.Run(Block block, int pos, StatementTransformContext con
113114
// if the method is a setter we're dealing with an object initializer
114115
// if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer
115116
while (pos + initializerItemsCount + 1 < block.Instructions.Count
116-
&& IsPartOfInitializer(block.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockKind, context))
117+
&& IsPartOfInitializer(block.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockKind, ref initializerContainsInitOnlyItems, context))
117118
{
118119
initializerItemsCount++;
119120
}
120121
// Do not convert the statements into an initializer if there's an incompatible usage of the initializer variable
121122
// directly after the possible initializer.
122-
if (IsMethodCallOnVariable(block.Instructions[pos + initializerItemsCount + 1], v))
123+
if (!initializerContainsInitOnlyItems && IsMethodCallOnVariable(block.Instructions[pos + initializerItemsCount + 1], v))
123124
return;
124125
// Calculate the correct number of statements inside the initializer:
125126
// All index variables that were used in the initializer have Index set to -1.
@@ -200,7 +201,7 @@ bool IsMethodCallOnVariable(ILInstruction inst, ILVariable variable)
200201
bool isCollection;
201202
readonly Stack<HashSet<AccessPathElement>> pathStack = new Stack<HashSet<AccessPathElement>>();
202203

203-
bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockKind blockKind, StatementTransformContext context)
204+
bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockKind blockKind, ref bool initializerContainsInitOnlyItems, StatementTransformContext context)
204205
{
205206
// Include any stores to local variables that are single-assigned and do not reference the initializer-variable
206207
// in the list of possible index variables.
@@ -255,6 +256,7 @@ bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int
255256
return false;
256257
if (blockKind != BlockKind.ObjectInitializer && blockKind != BlockKind.WithInitializer)
257258
blockKind = BlockKind.ObjectInitializer;
259+
initializerContainsInitOnlyItems |= lastElement.Member is IProperty { Setter.IsInitOnly: true };
258260
return true;
259261
default:
260262
return false;

0 commit comments

Comments
 (0)