Facilitate the merge
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / ElementInit.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. 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  Microsoft Public License, 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 Microsoft Public License.
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.Reflection;
20 using System.Text;
21 using System.Dynamic.Utils;
22
23 #if SILVERLIGHT
24 using System.Core;
25 #endif
26
27 #if CLR2
28 namespace Microsoft.Scripting.Ast {
29 #else
30 namespace System.Linq.Expressions {
31 #endif
32     /// <summary>
33     /// Represents the initialization of a list.
34     /// </summary>
35     public sealed class ElementInit : IArgumentProvider {
36         private MethodInfo _addMethod;
37         private ReadOnlyCollection<Expression> _arguments;
38
39         internal ElementInit(MethodInfo addMethod, ReadOnlyCollection<Expression> arguments) {
40             _addMethod = addMethod;
41             _arguments = arguments;
42         }
43         /// <summary>
44         /// Gets the <see cref="MethodInfo"/> used to add elements to the object.
45         /// </summary>
46         public MethodInfo AddMethod {
47             get { return _addMethod; }
48         }
49
50         /// <summary>
51         /// Gets the list of elements to be added to the object.
52         /// </summary>
53         public ReadOnlyCollection<Expression> Arguments {
54             get { return _arguments; }
55         }
56
57         Expression IArgumentProvider.GetArgument(int index) {
58             return _arguments[index];
59         }
60
61         int IArgumentProvider.ArgumentCount {
62             get {
63                 return _arguments.Count;
64             }
65         }
66
67         /// <summary>
68         /// Creates a <see cref="String"/> representation of the node.
69         /// </summary>
70         /// <returns>A <see cref="String"/> representation of the node.</returns>
71         public override string ToString() {
72             return ExpressionStringBuilder.ElementInitBindingToString(this);
73         }
74
75         /// <summary>
76         /// Creates a new expression that is like this one, but using the
77         /// supplied children. If all of the children are the same, it will
78         /// return this expression.
79         /// </summary>
80         /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
81         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
82         public ElementInit Update(IEnumerable<Expression> arguments) {
83             if (arguments == Arguments) {
84                 return this;
85             }
86             return Expression.ElementInit(AddMethod, arguments);
87         }
88     }
89
90
91     public partial class Expression {
92         /// <summary>
93         /// Creates an <see cref="T:ElementInit">ElementInit</see> expression that represents the initialization of a list.
94         /// </summary>
95         /// <param name="addMethod">The <see cref="MethodInfo"/> for the list's Add method.</param>
96         /// <param name="arguments">An array containing the Expressions to be used to initialize the list.</param>
97         /// <returns>The created <see cref="T:ElementInit">ElementInit</see> expression.</returns>
98         public static ElementInit ElementInit(MethodInfo addMethod, params Expression[] arguments) {
99             return ElementInit(addMethod, arguments as IEnumerable<Expression>);
100         }
101
102         /// <summary>
103         /// Creates an <see cref="T:ElementInit">ElementInit</see> expression that represents the initialization of a list.
104         /// </summary>
105         /// <param name="addMethod">The <see cref="MethodInfo"/> for the list's Add method.</param>
106         /// <param name="arguments">An <see cref="IEnumerable{T}"/> containing <see cref="Expression"/> elements to initialize the list.</param>
107         /// <returns>The created <see cref="T:ElementInit">ElementInit</see> expression.</returns>
108         public static ElementInit ElementInit(MethodInfo addMethod, IEnumerable<Expression> arguments) {
109             ContractUtils.RequiresNotNull(addMethod, "addMethod");
110             ContractUtils.RequiresNotNull(arguments, "arguments");
111
112             var argumentsRO = arguments.ToReadOnly();
113
114             RequiresCanRead(argumentsRO, "arguments");
115             ValidateElementInitAddMethodInfo(addMethod);
116             ValidateArgumentTypes(addMethod, ExpressionType.Call, ref argumentsRO);
117             return new ElementInit(addMethod, argumentsRO);
118         }
119
120         private static void ValidateElementInitAddMethodInfo(MethodInfo addMethod) {
121             ValidateMethodInfo(addMethod);
122             ParameterInfo[] pis = addMethod.GetParametersCached();
123             if (pis.Length == 0) {
124                 throw Error.ElementInitializerMethodWithZeroArgs();
125             }
126             if (!addMethod.Name.Equals("Add", StringComparison.OrdinalIgnoreCase)) {
127                 throw Error.ElementInitializerMethodNotAdd();
128             }
129             if (addMethod.IsStatic) {
130                 throw Error.ElementInitializerMethodStatic();
131             }
132             foreach (ParameterInfo pi in pis) {
133                 if (pi.ParameterType.IsByRef) {
134                     throw Error.ElementInitializerMethodNoRefOutParam(pi.Name, addMethod.Name);
135                 }
136             }
137         }
138     }
139 }