Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / ListInitExpression.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Reflection;
22 using System.Runtime.CompilerServices;
23
24 #if !FEATURE_CORE_DLR
25 namespace Microsoft.Scripting.Ast {
26 #else
27 namespace System.Linq.Expressions {
28 #endif
29     /// <summary>
30     /// Represents a constructor call that has a collection initializer.
31     /// </summary>
32     /// <remarks>
33     /// Use the <see cref="M:ListInit"/> factory methods to create a ListInitExpression. 
34     /// The value of the NodeType property of a ListInitExpression is ListInit. 
35     /// </remarks>
36     [DebuggerTypeProxy(typeof(Expression.ListInitExpressionProxy))]
37     public sealed class ListInitExpression : Expression {
38         private readonly NewExpression _newExpression;
39         private readonly ReadOnlyCollection<ElementInit> _initializers;
40
41         internal ListInitExpression(NewExpression newExpression, ReadOnlyCollection<ElementInit> initializers) {
42             _newExpression = newExpression;
43             _initializers = initializers;
44         }
45
46         /// <summary>
47         /// Returns the node type of this <see cref="Expression"/>. (Inherited from <see cref="Expression" />.)
48         /// </summary>
49         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
50         public sealed override ExpressionType NodeType {
51             get { return ExpressionType.ListInit; }
52         }
53
54         /// <summary>
55         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
56         /// </summary>
57         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
58         public sealed override Type Type {
59             get { return _newExpression.Type; }
60         }
61
62         /// <summary>
63         /// Gets a value that indicates whether the expression tree node can be reduced. 
64         /// </summary>
65         public override bool CanReduce {
66             get {
67                 return true;
68             }
69         }
70
71         /// <summary>
72         /// Gets the expression that contains a call to the constructor of a collection type. 
73         /// </summary>
74         public NewExpression NewExpression {
75             get { return _newExpression; }
76         }
77
78         /// <summary>
79         /// Gets the element initializers that are used to initialize a collection. 
80         /// </summary>
81         public ReadOnlyCollection<ElementInit> Initializers {
82             get { return _initializers; }
83         }
84
85         /// <summary>
86         /// Dispatches to the specific visit method for this node type.
87         /// </summary>
88         protected internal override Expression Accept(ExpressionVisitor visitor) {
89             return visitor.VisitListInit(this);
90         }
91
92         /// <summary>
93         /// Reduces the binary expression node to a simpler expression. 
94         /// If CanReduce returns true, this should return a valid expression.
95         /// This method is allowed to return another node which itself 
96         /// must be reduced.
97         /// </summary>
98         /// <returns>The reduced expression.</returns>
99         public override Expression Reduce() {
100             return MemberInitExpression.ReduceListInit(_newExpression, _initializers, true);
101         }
102
103         /// <summary>
104         /// Creates a new expression that is like this one, but using the
105         /// supplied children. If all of the children are the same, it will
106         /// return this expression.
107         /// </summary>
108         /// <param name="newExpression">The <see cref="NewExpression" /> property of the result.</param>
109         /// <param name="initializers">The <see cref="Initializers" /> property of the result.</param>
110         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
111         public ListInitExpression Update(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
112             if (newExpression == NewExpression && initializers == Initializers) {
113                 return this;
114             }
115             return Expression.ListInit(newExpression, initializers);
116         }
117     }
118
119
120     public partial class Expression {
121         /// <summary>
122         /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
123         /// </summary>
124         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
125         /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
126         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
127         public static ListInitExpression ListInit(NewExpression newExpression, params Expression[] initializers) {
128             ContractUtils.RequiresNotNull(newExpression, "newExpression");
129             ContractUtils.RequiresNotNull(initializers, "initializers");
130             return ListInit(newExpression, initializers as IEnumerable<Expression>);
131         }
132
133         /// <summary>
134         /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
135         /// </summary>
136         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
137         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
138         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
139         public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<Expression> initializers) {
140             ContractUtils.RequiresNotNull(newExpression, "newExpression");
141             ContractUtils.RequiresNotNull(initializers, "initializers");
142
143             var initializerlist = initializers.ToReadOnly();
144             if (initializerlist.Count == 0) {
145                 throw Error.ListInitializerWithZeroMembers();
146             }
147
148             MethodInfo addMethod = FindMethod(newExpression.Type, "Add", null, new Expression[] { initializerlist[0] }, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
149             return ListInit(newExpression, addMethod, initializers);
150         }
151
152         /// <summary>
153         /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection. 
154         /// </summary>
155         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
156         /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
157         /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
158         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
159         public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, params Expression[] initializers) {
160             if (addMethod == null) {
161                 return ListInit(newExpression, initializers as IEnumerable<Expression>);
162             }
163             ContractUtils.RequiresNotNull(newExpression, "newExpression");
164             ContractUtils.RequiresNotNull(initializers, "initializers");
165             return ListInit(newExpression, addMethod, initializers as IEnumerable<Expression>);
166         }
167
168         /// <summary>
169         /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection. 
170         /// </summary>
171         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
172         /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
173         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="Expression"/> objects to use to populate the Initializers collection.</param>
174         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
175         public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers) {
176             if (addMethod == null) {
177                 return ListInit(newExpression, initializers);
178             }
179             ContractUtils.RequiresNotNull(newExpression, "newExpression");
180             ContractUtils.RequiresNotNull(initializers, "initializers");
181
182             var initializerlist = initializers.ToReadOnly();
183             if (initializerlist.Count == 0) {
184                 throw Error.ListInitializerWithZeroMembers();
185             }
186             ElementInit[] initList = new ElementInit[initializerlist.Count];
187             for (int i = 0; i < initializerlist.Count; i++) {
188                 initList[i] = ElementInit(addMethod, initializerlist[i]);
189             }
190             return ListInit(newExpression, new TrueReadOnlyCollection<ElementInit>(initList));
191         }
192
193         /// <summary>
194         /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection. 
195         /// </summary>
196         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
197         /// <param name="initializers">An array that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
198         /// <returns>
199         /// A <see cref="ListInitExpression"/> that has the <see cref="P:Expressions.NodeType"/> property equal to ListInit 
200         /// and the <see cref="P:ListInitExpression.NewExpression"/> and <see cref="P:ListInitExpression.Initializers"/> properties set to the specified values.
201         /// </returns>
202         /// <remarks>
203         /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>. 
204         /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type. 
205         /// </remarks>
206         public static ListInitExpression ListInit(NewExpression newExpression, params ElementInit[] initializers) {
207             return ListInit(newExpression, (IEnumerable<ElementInit>)initializers);
208         }
209
210         /// <summary>
211         /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection. 
212         /// </summary>
213         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
214         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
215         /// <returns>An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</returns>
216         /// <remarks>
217         /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>. 
218         /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type. 
219         /// </remarks>
220         public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
221             ContractUtils.RequiresNotNull(newExpression, "newExpression");
222             ContractUtils.RequiresNotNull(initializers, "initializers");
223             var initializerlist = initializers.ToReadOnly();
224             if (initializerlist.Count == 0) {
225                 throw Error.ListInitializerWithZeroMembers();
226             }
227             ValidateListInitArgs(newExpression.Type, initializerlist);
228             return new ListInitExpression(newExpression, initializerlist);
229         }
230     }
231 }