System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / NewExpression.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 SILVERLIGHT
25 using System.Core;
26 #endif
27
28 #if CLR2
29 namespace Microsoft.Scripting.Ast {
30 #else
31 namespace System.Linq.Expressions {
32 #endif
33
34     /// <summary>
35     /// Represents a constructor call.
36     /// </summary>
37 #if !SILVERLIGHT
38     [DebuggerTypeProxy(typeof(Expression.NewExpressionProxy))]
39 #endif
40     public class NewExpression : Expression, IArgumentProvider {
41         private readonly ConstructorInfo _constructor;
42         private IList<Expression> _arguments;
43         private readonly ReadOnlyCollection<MemberInfo> _members;
44
45         internal NewExpression(ConstructorInfo constructor, IList<Expression> arguments, ReadOnlyCollection<MemberInfo> members) {
46             _constructor = constructor;
47             _arguments = arguments;
48             _members = members;
49         }
50
51         /// <summary>
52         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
53         /// </summary>
54         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
55         public override Type Type {
56             get { return _constructor.DeclaringType; }
57         }
58
59         /// <summary>
60         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
61         /// </summary>
62         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
63         public sealed override ExpressionType NodeType {
64             get { return ExpressionType.New; }
65         }
66
67         /// <summary>
68         /// Gets the called constructor.
69         /// </summary>
70         public ConstructorInfo Constructor {
71             get { return _constructor; }
72         }
73
74         /// <summary>
75         /// Gets the arguments to the constructor.
76         /// </summary>
77         public ReadOnlyCollection<Expression> Arguments {
78             get { return ReturnReadOnly(ref _arguments); }
79         }
80
81         Expression IArgumentProvider.GetArgument(int index) {
82             return _arguments[index];
83         }
84
85         int IArgumentProvider.ArgumentCount {
86             get {
87                 return _arguments.Count;
88             }
89         }
90
91         /// <summary>
92         /// Gets the members that can retrieve the values of the fields that were initialized with constructor arguments.
93         /// </summary>
94         public ReadOnlyCollection<MemberInfo> Members {
95             get { return _members; }
96         }
97
98         /// <summary>
99         /// Dispatches to the specific visit method for this node type.
100         /// </summary>
101         protected internal override Expression Accept(ExpressionVisitor visitor) {
102             return visitor.VisitNew(this);
103         }
104
105         /// <summary>
106         /// Creates a new expression that is like this one, but using the
107         /// supplied children. If all of the children are the same, it will
108         /// return this expression.
109         /// </summary>
110         /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
111         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
112         public NewExpression Update(IEnumerable<Expression> arguments) {
113             if (arguments == Arguments) {
114                 return this;
115             }
116             if (Members != null) {
117                 return Expression.New(Constructor, arguments, Members);
118             }
119             return Expression.New(Constructor, arguments);
120         }
121     }
122
123     internal class NewValueTypeExpression : NewExpression {
124         private readonly Type _valueType;
125
126         internal NewValueTypeExpression(Type type, ReadOnlyCollection<Expression> arguments, ReadOnlyCollection<MemberInfo> members)
127             : base(null, arguments, members) {
128             _valueType = type;
129         }
130
131         public sealed override Type Type {
132             get { return _valueType; }
133         }
134     }
135
136     public partial class Expression {
137
138         /// <summary>
139         /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments. 
140         /// </summary>
141         /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
142         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> property set to the specified value.</returns>
143         public static NewExpression New(ConstructorInfo constructor) {
144             return New(constructor, (IEnumerable<Expression>)null);
145         }
146
147
148         /// <summary>
149         /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments. 
150         /// </summary>
151         /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
152         /// <param name="arguments">An array of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
153         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> and <see cref="P:Arguments"/> properties set to the specified value.</returns>
154         public static NewExpression New(ConstructorInfo constructor, params Expression[] arguments) {
155             return New(constructor, (IEnumerable<Expression>)arguments);
156         }
157
158
159         /// <summary>
160         /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments. 
161         /// </summary>
162         /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
163         /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
164         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> and <see cref="P:Arguments"/> properties set to the specified value.</returns>
165         public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments) {
166             ContractUtils.RequiresNotNull(constructor, "constructor");
167             ContractUtils.RequiresNotNull(constructor.DeclaringType, "constructor.DeclaringType");
168             TypeUtils.ValidateType(constructor.DeclaringType);
169             var argList = arguments.ToReadOnly();
170             ValidateArgumentTypes(constructor, ExpressionType.New, ref argList);
171
172             return new NewExpression(constructor, argList, null);
173         }
174
175
176         /// <summary>
177         /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor with the specified arguments. The members that access the constructor initialized fields are specified. 
178         /// </summary>
179         /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
180         /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
181         /// <param name="members">An <see cref="IEnumerable{T}"/> of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
182         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/>, <see cref="P:Arguments"/> and <see cref="P:Members"/> properties set to the specified value.</returns>
183         public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members) {
184             ContractUtils.RequiresNotNull(constructor, "constructor");
185             var memberList = members.ToReadOnly();
186             var argList = arguments.ToReadOnly();
187             ValidateNewArgs(constructor, ref argList, ref memberList);
188             return new NewExpression(constructor, argList, memberList);
189         }
190
191
192         /// <summary>
193         /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor with the specified arguments. The members that access the constructor initialized fields are specified. 
194         /// </summary>
195         /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
196         /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
197         /// <param name="members">An Array of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
198         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/>, <see cref="P:Arguments"/> and <see cref="P:Members"/> properties set to the specified value.</returns>
199         public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo[] members) {
200             return New(constructor, arguments, (IEnumerable<MemberInfo>)members);
201         }
202
203
204         /// <summary>
205         /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type. 
206         /// </summary>
207         /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments. </param>
208         /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to New and the Constructor property set to the ConstructorInfo that represents the parameterless constructor of the specified type.</returns>
209         public static NewExpression New(Type type) {
210             ContractUtils.RequiresNotNull(type, "type");
211             if (type == typeof(void)) {
212                 throw Error.ArgumentCannotBeOfTypeVoid();
213             }
214             ConstructorInfo ci = null;
215             if (!type.IsValueType) {
216                 ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, System.Type.EmptyTypes, null);
217                 if (ci == null) {
218                     throw Error.TypeMissingDefaultConstructor(type);
219                 }
220                 return New(ci);
221             }
222             return new NewValueTypeExpression(type, EmptyReadOnlyCollection<Expression>.Instance, null);
223         }
224
225
226
227         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
228         private static void ValidateNewArgs(ConstructorInfo constructor, ref ReadOnlyCollection<Expression> arguments, ref ReadOnlyCollection<MemberInfo> members) {
229             ParameterInfo[] pis;
230             if ((pis = constructor.GetParametersCached()).Length > 0) {
231                 if (arguments.Count != pis.Length) {
232                     throw Error.IncorrectNumberOfConstructorArguments();
233                 }
234                 if (arguments.Count != members.Count) {
235                     throw Error.IncorrectNumberOfArgumentsForMembers();
236                 }
237                 Expression[] newArguments = null;
238                 MemberInfo[] newMembers = null;
239                 for (int i = 0, n = arguments.Count; i < n; i++) {
240                     Expression arg = arguments[i];
241                     RequiresCanRead(arg, "argument");
242                     MemberInfo member = members[i];
243                     ContractUtils.RequiresNotNull(member, "member");
244                     if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType)) {
245                         throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType.Name);
246                     }
247                     Type memberType;
248                     ValidateAnonymousTypeMember(ref member, out memberType);
249                     if (!TypeUtils.AreReferenceAssignable(memberType, arg.Type)) {
250                         if (!TryQuote(memberType, ref arg)) {
251                             throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType);
252                         }
253                     }
254                     ParameterInfo pi = pis[i];
255                     Type pType = pi.ParameterType;
256                     if (pType.IsByRef) {
257                         pType = pType.GetElementType();
258                     }
259                     if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
260                         if (!TryQuote(pType, ref arg)) {
261                             throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
262                         }
263                     }
264                     if (newArguments == null && arg != arguments[i]) {
265                         newArguments = new Expression[arguments.Count];
266                         for (int j = 0; j < i; j++) {
267                             newArguments[j] = arguments[j];
268                         }
269                     }
270                     if (newArguments != null) {
271                         newArguments[i] = arg;
272                     }
273
274                     if (newMembers == null && member != members[i]) {
275                         newMembers = new MemberInfo[members.Count];
276                         for (int j = 0; j < i; j++) {
277                             newMembers[j] = members[j];
278                         }
279                     }
280                     if (newMembers != null) {
281                         newMembers[i] = member;
282                     }
283                 }
284                 if (newArguments != null) {
285                     arguments = new TrueReadOnlyCollection<Expression>(newArguments);
286                 }
287                 if (newMembers != null) {
288                     members = new TrueReadOnlyCollection<MemberInfo>(newMembers);
289                 }
290             } else if (arguments != null && arguments.Count > 0) {
291                 throw Error.IncorrectNumberOfConstructorArguments();
292             } else if (members != null && members.Count > 0) {
293                 throw Error.IncorrectNumberOfMembersForGivenConstructor();
294             }
295         }
296
297
298         private static void ValidateAnonymousTypeMember(ref MemberInfo member, out Type memberType) {
299             switch (member.MemberType) {
300                 case MemberTypes.Field:
301                     FieldInfo field = member as FieldInfo;
302                     if (field.IsStatic) {
303                         throw Error.ArgumentMustBeInstanceMember();
304                     }
305                     memberType = field.FieldType;
306                     return;
307                 case MemberTypes.Property:
308                     PropertyInfo pi = member as PropertyInfo;
309                     if (!pi.CanRead) {
310                         throw Error.PropertyDoesNotHaveGetter(pi);
311                     }
312                     if (pi.GetGetMethod().IsStatic) {
313                         throw Error.ArgumentMustBeInstanceMember();
314                     }
315                     memberType = pi.PropertyType;
316                     return;
317                 case MemberTypes.Method:
318                     MethodInfo method = member as MethodInfo;
319                     if (method.IsStatic) {
320                         throw Error.ArgumentMustBeInstanceMember();
321                     }
322 #if SILVERLIGHT
323                     if (SilverlightQuirks) {
324                         // we used to just store the MethodInfo
325                         memberType = method.ReturnType;
326                         return;
327                     }
328 #endif
329                     PropertyInfo prop = GetProperty(method);
330                     member = prop;
331                     memberType = prop.PropertyType;
332                     return;
333                 default:
334                     throw Error.ArgumentMustBeFieldInfoOrPropertInfoOrMethod();
335             }
336             // don't add code here, we've already returned
337         }
338     }
339 }