From dcd8fcbc3d2c819ff4f8b4c1aa758efd0ce3359b Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Thu, 4 May 2017 14:05:17 -0700 Subject: [PATCH] IObjectCreationExpression API Change There are couple of changes here: 1. API change: `ImmutableArray MemberInitializers` is changed to `ImmutableArray Initializers`. 2. Implementation changes: 1. Instead of returning the member initializers as synthesized ISymbolInitializer nodes, we now return member intializers as IAssignmentExpression nodes. This ensures completeness of IOperation tree. 2. Now we also return the collection intializer expressions within an object creation expression. Fixes #18115 There are 2 bugs still affecting this area: 1. #18781: IOperation API shape for collection initializer expressions 2. #19276: Missing Field/Property reference expression nodes in object creation initializer node --- .../CSharp/Portable/BoundTree/Expression.cs | 38 +-- .../CSharpCompilerSemanticTest.csproj | 1 + ...perationTests_IObjectCreationExpression.cs | 254 +++++++++++++++++ ...tionTests_IParameterReferenceExpression.cs | 44 +-- .../IOperationTests_ISymbolInitializer.cs | 108 ------- .../Generated/Operations.xml.Generated.cs | 6 +- .../Operations/IObjectCreationExpression.cs | 4 +- .../Portable/Operations/OperationWalker.cs | 2 +- .../Portable/BoundTree/Expression.vb | 30 +- .../Semantic/BasicCompilerSemanticTest.vbproj | 1 + ...perationTests_IObjectCreationExpression.vb | 265 ++++++++++++++++++ ...tionTests_IParameterReferenceExpression.vb | 53 ++-- .../IOperationTests_ISymbolInitializer.vb | 94 ------- .../Compilation/OperationTreeVerifier.cs | 2 +- 14 files changed, 590 insertions(+), 312 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.cs create mode 100644 src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.vb diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs index 605ada05830fa..4329f117fca05 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs @@ -515,43 +515,7 @@ internal partial class BoundObjectCreationExpression : IObjectCreationExpression ImmutableArray IHasArgumentsExpression.ArgumentsInEvaluationOrder => BoundCall.DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Constructor.Parameters, this.Syntax); - ImmutableArray IObjectCreationExpression.MemberInitializers - { - get - { - return (ImmutableArray)s_memberInitializersMappings.GetValue(this, - objectCreationExpression => - { - var objectInitializerExpression = this.InitializerExpressionOpt as BoundObjectInitializerExpression; - if (objectInitializerExpression != null) - { - var builder = ArrayBuilder.GetInstance(objectInitializerExpression.Initializers.Length); - foreach (var memberAssignment in objectInitializerExpression.Initializers) - { - var assignment = memberAssignment as BoundAssignmentOperator; - var leftSymbol = (assignment?.Left as BoundObjectInitializerMember)?.MemberSymbol; - - if ((object)leftSymbol == null) - { - continue; - } - - switch (leftSymbol.Kind) - { - case SymbolKind.Field: - builder.Add(new FieldInitializer(assignment.Syntax, (IFieldSymbol)leftSymbol, assignment.Right)); - break; - case SymbolKind.Property: - builder.Add(new PropertyInitializer(assignment.Syntax, (IPropertySymbol)leftSymbol, assignment.Right)); - break; - } - } - return builder.ToImmutableAndFree(); - } - return ImmutableArray.Empty; - }); - } - } + ImmutableArray IObjectCreationExpression.Initializers => GetChildInitializers(this.InitializerExpressionOpt).As(); internal static ImmutableArray GetChildInitializers(BoundExpression objectOrCollectionInitializer) { diff --git a/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj b/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj index 9858091851294..4c1aefc953288 100644 --- a/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj +++ b/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj @@ -63,6 +63,7 @@ + diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.cs new file mode 100644 index 0000000000000..2a5b571057c7d --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.cs @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public partial class IOperationTests : SemanticModelTestBase + { + [Fact, WorkItem(17588, "https://github.com/dotnet/roslyn/issues/17588")] + public void ObjectCreationWithMemberInitializers() + { + string source = @" +struct B +{ + public bool Field; +} + +class F +{ + public int Field; + public string Property1 { set; get; } + public B Property2 { set; get; } +} + +class C +{ + public void M1() + /**/{ + var x1 = new F(); + var x2 = new F() { Field = 2 }; + var x3 = new F() { Property1 = """" }; + var x4 = new F() { Property1 = """", Field = 2 }; + var x5 = new F() { Property2 = new B { Field = true } }; + + var e1 = new F() { Property2 = 1 }; + var e2 = new F() { """" }; + }/**/ +} +"; + string expectedOperationTree = @" +IBlockStatement (7 statements, 7 locals) (OperationKind.BlockStatement, IsInvalid) (Syntax: '{ ... }') + Locals: Local_1: F x1 + Local_2: F x2 + Local_3: F x3 + Local_4: F x4 + Local_5: F x5 + Local_6: F e1 + Local_7: F e2 + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x1 = new F();') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x1 = new F();') + Variables: Local_1: F x1 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F()') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x2 = ne ... ield = 2 };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x2 = ne ... ield = 2 };') + Variables: Local_1: F x2 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { Field = 2 }') + Initializers(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'Field = 2') + Left: IOperation: (OperationKind.None) (Syntax: 'Field') + Right: ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x3 = ne ... ty1 = """" };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x3 = ne ... ty1 = """" };') + Variables: Local_1: F x3 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... rty1 = """" }') + Initializers(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.String) (Syntax: 'Property1 = """"') + Left: IOperation: (OperationKind.None) (Syntax: 'Property1') + Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x4 = ne ... ield = 2 };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x4 = ne ... ield = 2 };') + Variables: Local_1: F x4 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... Field = 2 }') + Initializers(2): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.String) (Syntax: 'Property1 = """"') + Left: IOperation: (OperationKind.None) (Syntax: 'Property1') + Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'Field = 2') + Left: IOperation: (OperationKind.None) (Syntax: 'Field') + Right: ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x5 = ne ... = true } };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x5 = ne ... = true } };') + Variables: Local_1: F x5 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... = true } }') + Initializers(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: B) (Syntax: 'Property2 = ... ld = true }') + Left: IOperation: (OperationKind.None) (Syntax: 'Property2') + Right: IObjectCreationExpression (Constructor: B..ctor()) (OperationKind.ObjectCreationExpression, Type: B) (Syntax: 'new B { Field = true }') + Initializers(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Boolean) (Syntax: 'Field = true') + Left: IOperation: (OperationKind.None) (Syntax: 'Field') + Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Boolean, Constant: True) (Syntax: 'true') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e1 = ne ... rty2 = 1 };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var e1 = ne ... rty2 = 1 };') + Variables: Local_1: F e1 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { P ... erty2 = 1 }') + Initializers(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: B, IsInvalid) (Syntax: 'Property2 = 1') + Left: IOperation: (OperationKind.None) (Syntax: 'Property2') + Right: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: B, IsInvalid) (Syntax: '1') + ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e2 = new F() { """" };') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var e2 = new F() { """" };') + Variables: Local_1: F e2 + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { """" }') + Initializers(1): IInvalidExpression (OperationKind.InvalidExpression, Type: ?, IsInvalid) (Syntax: '""""') + Children(1): ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0029: Cannot implicitly convert type 'int' to 'B' + // var e1 = new F() { Property2 = 1 }; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "B").WithLocation(24, 40), + // CS1922: Cannot initialize type 'F' with a collection initializer because it does not implement 'System.Collections.IEnumerable' + // var e2 = new F() { "" }; + Diagnostic(ErrorCode.ERR_CollectionInitRequiresIEnumerable, @"{ """" }").WithArguments("F").WithLocation(25, 26) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact, WorkItem(17588, "https://github.com/dotnet/roslyn/issues/17588")] + public void ObjectCreationWithCollectionInitializer() + { + string source = @" +using System.Collections.Generic; + +class C +{ + private readonly int field; + public void M1(int x) + { + int y = 0; + var x1 = /**/new List { x, y, field }/**/; + } +} +"; + string expectedOperationTree = @" +IObjectCreationExpression (Constructor: System.Collections.Generic.List..ctor()) (OperationKind.ObjectCreationExpression, Type: System.Collections.Generic.List) (Syntax: 'new List(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact, WorkItem(17588, "https://github.com/dotnet/roslyn/issues/17588")] + public void ObjectCreationWithNestedCollectionInitializer() + { + string source = @" +using System.Collections.Generic; +using System.Linq; + +class C +{ + private readonly int field = 0; + public void M1(int x) + { + int y = 0; + var x1 = /**/new List> { + new[] { x, y }.ToList(), + new List { field } + }/**/; + } +} +"; + string expectedOperationTree = @" +IObjectCreationExpression (Constructor: System.Collections.Generic.List>..ctor()) (OperationKind.ObjectCreationExpression, Type: System.Collections.Generic.List>) (Syntax: 'new List
  • System.Linq.Enumerable.ToList(this System.Collections.Generic.IEnumerable source)) (OperationKind.InvocationExpression, Type: System.Collections.Generic.List) (Syntax: 'new[] { x, y }.ToList()') + Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: source) (OperationKind.Argument) (Syntax: 'new[] { x, y }') + IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.Collections.Generic.IEnumerable) (Syntax: 'new[] { x, y }') + IArrayCreationExpression (Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[]) (Syntax: 'new[] { x, y }') + Dimension Sizes(1): ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: 'new[] { x, y }') + Initializer: IArrayInitializer (2 elements) (OperationKind.ArrayInitializer) (Syntax: '{ x, y }') + Element Values(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y') + IOperation: (OperationKind.None) (Syntax: 'new List { field }') + Children(1): IObjectCreationExpression (Constructor: System.Collections.Generic.List..ctor()) (OperationKind.ObjectCreationExpression, Type: System.Collections.Generic.List) (Syntax: 'new List { field }') + Initializers(1): IOperation: (OperationKind.None) (Syntax: 'field') + Children(1): IFieldReferenceExpression: System.Int32 C.field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'field') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'field') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact, WorkItem(17588, "https://github.com/dotnet/roslyn/issues/17588")] + public void ObjectCreationWithMemberAndCollectionInitializers() + { + string source = @" +using System.Collections.Generic; + +internal class Class +{ + public int X { get; set; } + public List Y { get; set; } + public Dictionary Z { get; set; } + public Class C { get; set; } + + private readonly int field = 0; + + public void M(int x) + { + int y = 0; + var c = /**/new Class() { + X = x, + Y = { x, y, 3 }, + Z = { { x, y } }, + C = { X = field } + }/**/; + } +} +"; + string expectedOperationTree = @" +IObjectCreationExpression (Constructor: Class..ctor()) (OperationKind.ObjectCreationExpression, Type: Class) (Syntax: 'new Class() ... }') + Initializers(4): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'X = x') + Left: IOperation: (OperationKind.None) (Syntax: 'X') + Right: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Collections.Generic.List) (Syntax: 'Y = { x, y, 3 }') + Left: IOperation: (OperationKind.None) (Syntax: 'Y') + Right: IOperation: (OperationKind.None) (Syntax: '{ x, y, 3 }') + Children(3): IOperation: (OperationKind.None) (Syntax: 'x') + Children(1): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + IOperation: (OperationKind.None) (Syntax: 'y') + Children(1): ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y') + IOperation: (OperationKind.None) (Syntax: '3') + Children(1): ILiteralExpression (Text: 3) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 3) (Syntax: '3') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Collections.Generic.Dictionary) (Syntax: 'Z = { { x, y } }') + Left: IOperation: (OperationKind.None) (Syntax: 'Z') + Right: IOperation: (OperationKind.None) (Syntax: '{ { x, y } }') + Children(1): IOperation: (OperationKind.None) (Syntax: '{ x, y }') + Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: Class) (Syntax: 'C = { X = field }') + Left: IOperation: (OperationKind.None) (Syntax: 'C') + Right: IOperation: (OperationKind.None) (Syntax: '{ X = field }') + Children(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'X = field') + Left: IOperation: (OperationKind.None) (Syntax: 'X') + Right: IFieldReferenceExpression: System.Int32 Class.field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'field') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Class) (Syntax: 'field') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + } +} \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.cs index 509772a22f199..9f62943ac058a 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.cs @@ -165,26 +165,30 @@ public void M(int x, int y, int z) "; string expectedOperationTree = @" IObjectCreationExpression (Constructor: Class..ctor()) (OperationKind.ObjectCreationExpression, Type: Class) (Syntax: 'new Class() ... { X = z } }') - Member Initializers(4): IPropertyInitializer (Property: System.Int32 Class.X { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'X = x') - IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') - IPropertyInitializer (Property: System.Collections.Generic.List Class.Y { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'Y = { x, y, 3 }') - IOperation: (OperationKind.None) (Syntax: '{ x, y, 3 }') - Children(3): IOperation: (OperationKind.None) (Syntax: 'x') - Children(1): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') - IOperation: (OperationKind.None) (Syntax: 'y') - Children(1): IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') - IOperation: (OperationKind.None) (Syntax: '3') - Children(1): ILiteralExpression (Text: 3) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 3) (Syntax: '3') - IPropertyInitializer (Property: System.Collections.Generic.Dictionary Class.Z { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'Z = { { x, y } }') - IOperation: (OperationKind.None) (Syntax: '{ { x, y } }') - Children(1): IOperation: (OperationKind.None) (Syntax: '{ x, y }') - Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') - IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') - IPropertyInitializer (Property: Class Class.C { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'C = { X = z }') - IOperation: (OperationKind.None) (Syntax: '{ X = z }') - Children(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'X = z') - Left: IOperation: (OperationKind.None) (Syntax: 'X') - Right: IParameterReferenceExpression: z (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'z') + Initializers(4): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'X = x') + Left: IOperation: (OperationKind.None) (Syntax: 'X') + Right: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Collections.Generic.List) (Syntax: 'Y = { x, y, 3 }') + Left: IOperation: (OperationKind.None) (Syntax: 'Y') + Right: IOperation: (OperationKind.None) (Syntax: '{ x, y, 3 }') + Children(3): IOperation: (OperationKind.None) (Syntax: 'x') + Children(1): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + IOperation: (OperationKind.None) (Syntax: 'y') + Children(1): IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') + IOperation: (OperationKind.None) (Syntax: '3') + Children(1): ILiteralExpression (Text: 3) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 3) (Syntax: '3') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Collections.Generic.Dictionary) (Syntax: 'Z = { { x, y } }') + Left: IOperation: (OperationKind.None) (Syntax: 'Z') + Right: IOperation: (OperationKind.None) (Syntax: '{ { x, y } }') + Children(1): IOperation: (OperationKind.None) (Syntax: '{ x, y }') + Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') + IAssignmentExpression (OperationKind.AssignmentExpression, Type: Class) (Syntax: 'C = { X = z }') + Left: IOperation: (OperationKind.None) (Syntax: 'C') + Right: IOperation: (OperationKind.None) (Syntax: '{ X = z }') + Children(1): IAssignmentExpression (OperationKind.AssignmentExpression, Type: System.Int32) (Syntax: 'X = z') + Left: IOperation: (OperationKind.None) (Syntax: 'X') + Right: IParameterReferenceExpression: z (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'z') "; var expectedDiagnostics = DiagnosticDescription.None; diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs index dbc5ed2c4157d..7dc638e30f762 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.cs @@ -332,113 +332,5 @@ class C VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } - - [Fact, WorkItem(17595, "https://github.com/dotnet/roslyn/issues/17595")] - public void MemberInitializerCSharp() - { - string source = @" -struct B -{ - public bool Field; -} - -class F -{ - public int Field; - public string Property1 { set; get; } - public B Property2 { set; get; } -} - -class C -{ - public void M1() - /**/{ - var x1 = new F(); - var x2 = new F() { Field = 2 }; - var x3 = new F() { Property1 = """""""" }; - var x4 = new F() { Property1 = """""""", Field = 2 }; - var x5 = new F() { Property2 = new B { Field = true } }; - - var e1 = new F() { Property2 = 1 }; - var e2 = new F() { """""""" }; - }/**/ -} -"; - string expectedOperationTree = @" -IBlockStatement (7 statements, 7 locals) (OperationKind.BlockStatement, IsInvalid) (Syntax: '{ ... }') - Locals: Local_1: F x1 - Local_2: F x2 - Local_3: F x3 - Local_4: F x4 - Local_5: F x5 - Local_6: F e1 - Local_7: F e2 - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x1 = new F();') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x1 = new F();') - Variables: Local_1: F x1 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F()') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x2 = ne ... ield = 2 };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x2 = ne ... ield = 2 };') - Variables: Local_1: F x2 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { Field = 2 }') - Member Initializers(1): IFieldInitializer (Field: System.Int32 F.Field) (OperationKind.FieldInitializerInCreation) (Syntax: 'Field = 2') - ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var x3 = ne ... 1 = """""""" };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var x3 = ne ... 1 = """""""" };') - Variables: Local_1: F x3 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { P ... y1 = """""""" }') - Member Initializers(1): IPropertyInitializer (Property: System.String F.Property1 { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'Property1 = """"') - ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var x4 = ne ... ield = 2 };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var x4 = ne ... ield = 2 };') - Variables: Local_1: F x4 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { P ... Field = 2 }') - Member Initializers(2): IPropertyInitializer (Property: System.String F.Property1 { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'Property1 = """"') - ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') - IFieldInitializer (Field: System.Int32 F.Field) (OperationKind.FieldInitializerInCreation) (Syntax: 'Field = 2') - ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x5 = ne ... = true } };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'var x5 = ne ... = true } };') - Variables: Local_1: F x5 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... = true } }') - Member Initializers(1): IPropertyInitializer (Property: B F.Property2 { get; set; }) (OperationKind.PropertyInitializerInCreation) (Syntax: 'Property2 = ... ld = true }') - IObjectCreationExpression (Constructor: B..ctor()) (OperationKind.ObjectCreationExpression, Type: B) (Syntax: 'new B { Field = true }') - Member Initializers(1): IFieldInitializer (Field: System.Boolean B.Field) (OperationKind.FieldInitializerInCreation) (Syntax: 'Field = true') - ILiteralExpression (OperationKind.LiteralExpression, Type: System.Boolean, Constant: True) (Syntax: 'true') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e1 = ne ... rty2 = 1 };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var e1 = ne ... rty2 = 1 };') - Variables: Local_1: F e1 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { P ... erty2 = 1 }') - Member Initializers(1): IPropertyInitializer (Property: B F.Property2 { get; set; }) (OperationKind.PropertyInitializerInCreation, IsInvalid) (Syntax: 'Property2 = 1') - IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: B, IsInvalid) (Syntax: '1') - ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1') - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e2 = ne ... ) { """""""" };') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'var e2 = ne ... ) { """""""" };') - Variables: Local_1: F e2 - Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { """""""" }') -"; - var expectedDiagnostics = new DiagnosticDescription[] { - // CS1003: Syntax error, ',' expected - // var x3 = new F() { Property1 = """" }; - Diagnostic(ErrorCode.ERR_SyntaxError, @"""""").WithArguments(",", "").WithLocation(20, 42), - // CS1003: Syntax error, ',' expected - // var x4 = new F() { Property1 = """", Field = 2 }; - Diagnostic(ErrorCode.ERR_SyntaxError, @"""""").WithArguments(",", "").WithLocation(21, 42), - // CS1003: Syntax error, ',' expected - // var e2 = new F() { """" }; - Diagnostic(ErrorCode.ERR_SyntaxError, @"""""").WithArguments(",", "").WithLocation(25, 30), - // CS0747: Invalid initializer member declarator - // var x3 = new F() { Property1 = """" }; - Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, @"""""").WithLocation(20, 42), - // CS0747: Invalid initializer member declarator - // var x4 = new F() { Property1 = """", Field = 2 }; - Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, @"""""").WithLocation(21, 42), - // CS0029: Cannot implicitly convert type 'int' to 'B' - // var e1 = new F() { Property2 = 1 }; - Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "B").WithLocation(24, 40) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); - } } } \ No newline at end of file diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index 93bd76bd27283..1188abb551c47 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -1522,11 +1522,11 @@ public override TResult Accept(OperationVisitor internal sealed partial class ObjectCreationExpression : Operation, IHasArgumentsExpression, IObjectCreationExpression { - public ObjectCreationExpression(IMethodSymbol constructor, ImmutableArray memberInitializers, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + public ObjectCreationExpression(IMethodSymbol constructor, ImmutableArray initializers, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(OperationKind.ObjectCreationExpression, isInvalid, syntax, type, constantValue) { Constructor = constructor; - MemberInitializers = memberInitializers; + Initializers = initializers; } /// /// Constructor to be invoked on the created instance. @@ -1535,7 +1535,7 @@ public ObjectCreationExpression(IMethodSymbol constructor, ImmutableArray /// Explicitly-specified member initializers. /// - public ImmutableArray MemberInitializers { get; } + public ImmutableArray Initializers { get; } public override void Accept(OperationVisitor visitor) { visitor.VisitObjectCreationExpression(this); diff --git a/src/Compilers/Core/Portable/Operations/IObjectCreationExpression.cs b/src/Compilers/Core/Portable/Operations/IObjectCreationExpression.cs index 9a06dedb54c60..dfe2997af5ae3 100644 --- a/src/Compilers/Core/Portable/Operations/IObjectCreationExpression.cs +++ b/src/Compilers/Core/Portable/Operations/IObjectCreationExpression.cs @@ -18,9 +18,9 @@ public interface IObjectCreationExpression : IHasArgumentsExpression /// IMethodSymbol Constructor { get; } /// - /// Explicitly-specified member initializers. + /// List of member or collection initializer expressions in the object initializer, if any. /// - ImmutableArray MemberInitializers { get; } + ImmutableArray Initializers { get; } } } diff --git a/src/Compilers/Core/Portable/Operations/OperationWalker.cs b/src/Compilers/Core/Portable/Operations/OperationWalker.cs index aeed5ce40c37d..f9798628922b0 100644 --- a/src/Compilers/Core/Portable/Operations/OperationWalker.cs +++ b/src/Compilers/Core/Portable/Operations/OperationWalker.cs @@ -345,7 +345,7 @@ public override void VisitAddressOfExpression(IAddressOfExpression operation) public override void VisitObjectCreationExpression(IObjectCreationExpression operation) { VisitArray(operation.ArgumentsInEvaluationOrder); - VisitArray(operation.MemberInitializers); + VisitArray(operation.Initializers); } public override void VisitFieldInitializer(IFieldInitializer operation) diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb b/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb index 029f3a6f4c820..73c08fcfe98c0 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb @@ -1155,8 +1155,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Partial Class BoundObjectCreationExpression Implements IObjectCreationExpression - Private Shared ReadOnly s_memberInitializersMappings As New System.Runtime.CompilerServices.ConditionalWeakTable(Of BoundObjectCreationExpression, Object) - Private ReadOnly Property IObjectCreationExpression_Constructor As IMethodSymbol Implements IObjectCreationExpression.Constructor Get Return Me.ConstructorOpt @@ -1170,31 +1168,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Private ReadOnly Property IObjectCreationExpression_MemberInitializers As ImmutableArray(Of ISymbolInitializer) Implements IObjectCreationExpression.MemberInitializers - Get - Dim initializer = s_memberInitializersMappings.GetValue(Me, Function(objectCreationStatement) - Dim objectInitializerExpression As BoundObjectInitializerExpressionBase = Me.InitializerOpt - If objectInitializerExpression IsNot Nothing Then - Dim builder = ArrayBuilder(Of ISymbolInitializer).GetInstance(objectInitializerExpression.Initializers.Length) - For Each memberAssignment In objectInitializerExpression.Initializers - Dim assignment = TryCast(memberAssignment, BoundAssignmentOperator) - Dim left = assignment?.Left - If left IsNot Nothing Then - Select Case left.Kind - Case BoundKind.FieldAccess - builder.Add(New FieldInitializer(assignment.Syntax, DirectCast(left, BoundFieldAccess).FieldSymbol, assignment.Right)) - Case BoundKind.PropertyAccess - builder.Add(New PropertyInitializer(assignment.Syntax, DirectCast(left, BoundPropertyAccess).PropertySymbol, assignment.Right)) - End Select - End If - Next - Return builder.ToImmutableAndFree() - End If - - Return ImmutableArray(Of ISymbolInitializer).Empty - End Function) - - Return DirectCast(initializer, ImmutableArray(Of ISymbolInitializer)) + Private ReadOnly Property IObjectCreationExpression_Initializers As ImmutableArray(Of IOperation) Implements IObjectCreationExpression.Initializers + Get + Return If(Me.InitializerOpt IsNot Nothing, Me.InitializerOpt.Initializers.As(Of IOperation), ImmutableArray(Of IOperation).Empty) End Get End Property diff --git a/src/Compilers/VisualBasic/Test/Semantic/BasicCompilerSemanticTest.vbproj b/src/Compilers/VisualBasic/Test/Semantic/BasicCompilerSemanticTest.vbproj index c12ac6254f277..019f9ff3a9530 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/BasicCompilerSemanticTest.vbproj +++ b/src/Compilers/VisualBasic/Test/Semantic/BasicCompilerSemanticTest.vbproj @@ -108,6 +108,7 @@ + diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.vb new file mode 100644 index 0000000000000..232e15217842b --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IObjectCreationExpression.vb @@ -0,0 +1,265 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Roslyn.Test.Utilities + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics + + Partial Public Class IOperationTests + Inherits SemanticModelTestBase + + + Public Sub ObjectCreationWithMemberInitializers() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + + VerifyOperationTreeAndDiagnosticsForTest(Of MethodBlockSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub ObjectCreationWithCollectionInitializer() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub ObjectCreationWithNestedCollectionInitializer() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub ObjectCreationWithMemberAndCollectionInitializers() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb index 65581f7e4b429..e3af89888feb6 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb @@ -226,7 +226,7 @@ IOperation: (OperationKind.None) (Syntax: 'From y In x ... nto Count()') VerifyOperationTreeAndDiagnosticsForTest(Of QueryExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) End Sub - + Public Sub ParameterReference_ObjectAndCollectionInitializer() Dim source = .Value +End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb index 974d686a259cc..42dcdd99240a6 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ISymbolInitializer.vb @@ -269,99 +269,5 @@ IFieldInitializer (Field: C.i2 As System.Int32) (OperationKind.FieldInitializerA VerifyOperationTreeAndDiagnosticsForTest(Of EqualsValueSyntax)(source, expectedOperationTree, expectedDiagnostics) End Sub - - - Public Sub MemberInitializer() - Dim source = .Value - - Dim expectedOperationTree = .Value - - Dim expectedDiagnostics = .Value - - VerifyOperationTreeAndDiagnosticsForTest(Of MethodBlockSyntax)(source, expectedOperationTree, expectedDiagnostics) - End Sub End Class End Namespace diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index 95209b461d02a..4a0e6df980f3c 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -879,7 +879,7 @@ public override void VisitObjectCreationExpression(IObjectCreationExpression ope LogCommonPropertiesAndNewLine(operation); VisitArguments(operation); - VisitArray(operation.MemberInitializers, "Member Initializers", logElementCount: true); + VisitArray(operation.Initializers, "Initializers", logElementCount: true); } public override void VisitFieldInitializer(IFieldInitializer operation)