PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_2_0/Src/Microsoft.Scripting.Core/Ast/IndexExpression.cs

#
C# | 284 lines | 201 code | 48 blank | 35 comment | 63 complexity | 3969e8e98ea827eb80a910376f2c2f96 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  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. using System; using Microsoft;
  16. using System.Collections.Generic;
  17. using System.Collections.ObjectModel;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using Microsoft.Scripting.Actions;
  21. using Microsoft.Scripting.Utils;
  22. using System.Text;
  23. namespace Microsoft.Linq.Expressions {
  24. /// <summary>
  25. /// Represents property or array indexing
  26. /// </summary>
  27. public sealed class IndexExpression : Expression {
  28. private readonly Expression _instance;
  29. private readonly PropertyInfo _indexer;
  30. private readonly ReadOnlyCollection<Expression> _arguments;
  31. internal IndexExpression(
  32. Expression instance,
  33. PropertyInfo indexer,
  34. Annotations annotations,
  35. ReadOnlyCollection<Expression> arguments,
  36. Type type,
  37. bool canRead,
  38. bool canWrite)
  39. : base(ExpressionType.Index, type, false, annotations, canRead, canWrite) {
  40. if (indexer == null) {
  41. Debug.Assert(instance != null && instance.Type.IsArray);
  42. Debug.Assert(instance.Type.GetArrayRank() == arguments.Count);
  43. Debug.Assert(instance.Type.GetElementType() == type);
  44. }
  45. _instance = instance;
  46. _indexer = indexer;
  47. _arguments = arguments;
  48. }
  49. public Expression Object {
  50. get { return _instance; }
  51. }
  52. /// <summary>
  53. /// If this is an indexed property, returns the property
  54. /// If this is an array indexing operation, returns null
  55. /// </summary>
  56. public PropertyInfo Indexer {
  57. get { return _indexer; }
  58. }
  59. public ReadOnlyCollection<Expression> Arguments {
  60. get { return _arguments; }
  61. }
  62. internal override void BuildString(StringBuilder builder) {
  63. Debug.Assert(builder != null);
  64. if (_instance != null) {
  65. _instance.BuildString(builder);
  66. } else {
  67. Debug.Assert(_indexer != null);
  68. builder.Append(_indexer.DeclaringType.Name);
  69. }
  70. if (_indexer != null) {
  71. builder.Append(".");
  72. builder.Append(_indexer.Name);
  73. }
  74. builder.Append("[");
  75. for (int i = 0, n = _arguments.Count; i < n; i++) {
  76. if (i > 0) {
  77. builder.Append(", ");
  78. }
  79. _arguments[i].BuildString(builder);
  80. }
  81. builder.Append("]");
  82. }
  83. internal override Expression Accept(ExpressionTreeVisitor visitor) {
  84. return visitor.VisitIndex(this);
  85. }
  86. }
  87. /// <summary>
  88. /// Factory methods.
  89. /// </summary>
  90. public partial class Expression {
  91. public static IndexExpression MakeIndex(Expression instance, PropertyInfo indexer, Annotations annotations, IEnumerable<Expression> arguments) {
  92. if (indexer != null) {
  93. return Property(instance, indexer, annotations, arguments);
  94. } else {
  95. return ArrayAccess(instance, annotations, arguments);
  96. }
  97. }
  98. #region ArrayAccess
  99. public static IndexExpression ArrayAccess(Expression array, params Expression[] indexes) {
  100. return ArrayAccess(array, null, (IEnumerable<Expression>)indexes);
  101. }
  102. public static IndexExpression ArrayAccess(Expression array, IEnumerable<Expression> indexes) {
  103. return ArrayAccess(array, null, indexes);
  104. }
  105. public static IndexExpression ArrayAccess(Expression array, Annotations annotations, params Expression[] indexes) {
  106. return ArrayAccess(array, annotations, (IEnumerable<Expression>)indexes);
  107. }
  108. public static IndexExpression ArrayAccess(Expression array, Annotations annotations, IEnumerable<Expression> indexes) {
  109. RequiresCanRead(array, "array");
  110. Type arrayType = array.Type;
  111. if (!arrayType.IsArray) {
  112. throw Error.ArgumentMustBeArray();
  113. }
  114. var indexList = indexes.ToReadOnly();
  115. if (arrayType.GetArrayRank() != indexList.Count) {
  116. throw Error.IncorrectNumberOfIndexes();
  117. }
  118. foreach (Expression e in indexList) {
  119. RequiresCanRead(e, "indexes");
  120. if (e.Type != typeof(int)) {
  121. throw Error.ArgumentMustBeArrayIndexType();
  122. }
  123. }
  124. return new IndexExpression(array, null, annotations, indexList, arrayType.GetElementType(), true, true);
  125. }
  126. #endregion
  127. #region Property
  128. public static IndexExpression Property(Expression instance, PropertyInfo indexer, params Expression[] arguments) {
  129. return Property(instance, indexer, null, (IEnumerable<Expression>)arguments);
  130. }
  131. public static IndexExpression Property(Expression instance, PropertyInfo indexer, IEnumerable<Expression> arguments) {
  132. return Property(instance, indexer, null, arguments);
  133. }
  134. public static IndexExpression Property(Expression instance, PropertyInfo indexer, Annotations annotations, params Expression[] arguments) {
  135. return Property(instance, indexer, annotations, (IEnumerable<Expression>)arguments);
  136. }
  137. public static IndexExpression Property(Expression instance, PropertyInfo indexer, Annotations annotations, IEnumerable<Expression> arguments) {
  138. var argList = arguments.ToReadOnly();
  139. ValidateIndexedProperty(instance, indexer, ref argList);
  140. return new IndexExpression(instance, indexer, annotations, argList, indexer.PropertyType, indexer.CanRead, indexer.CanWrite);
  141. }
  142. // CTS places no restrictions on properties (see ECMA-335 8.11.3),
  143. // so we validate that the property conforms to CLS rules here.
  144. //
  145. // TODO: Do we still need all of this now that we take PropertyInfo?
  146. // Does reflection help us out at all? Expression.Property skips all of
  147. // these checks, so either it needs more checks or we need less here.
  148. private static void ValidateIndexedProperty(Expression instance, PropertyInfo property, ref ReadOnlyCollection<Expression> argList) {
  149. // If both getter and setter specified, all their parameter types
  150. // should match, with exception of the last setter parameter which
  151. // should match the type returned by the get method.
  152. // Accessor parameters cannot be ByRef.
  153. ContractUtils.RequiresNotNull(property, "property");
  154. ContractUtils.Requires(!property.PropertyType.IsByRef, "property", Strings.PropertyCannotHaveRefType);
  155. ContractUtils.Requires(property.PropertyType != typeof(void), "property", Strings.PropertyTypeCannotBeVoid);
  156. ParameterInfo[] getParameters = null;
  157. MethodInfo getter = property.GetGetMethod(true);
  158. if (getter != null) {
  159. getParameters = getter.GetParametersCached();
  160. ValidateAccessor(instance, getter, getParameters, ref argList);
  161. }
  162. MethodInfo setter = property.GetSetMethod(true);
  163. if (setter != null) {
  164. ParameterInfo[] setParameters = setter.GetParametersCached();
  165. ContractUtils.Requires(setParameters.Length > 0, "property", Strings.SetterHasNoParams);
  166. // valueType is the type of the value passed to the setter (last parameter)
  167. Type valueType = setParameters[setParameters.Length - 1].ParameterType;
  168. ContractUtils.Requires(!valueType.IsByRef, "property", Strings.PropertyCannotHaveRefType);
  169. ContractUtils.Requires(setter.ReturnType == typeof(void), "property", Strings.SetterMustBeVoid);
  170. ContractUtils.Requires(property.PropertyType == valueType, "property", Strings.PropertyTyepMustMatchSetter);
  171. if (getter != null) {
  172. ContractUtils.Requires(!(getter.IsStatic ^ setter.IsStatic), "property", Strings.BothAccessorsMustBeStatic);
  173. ContractUtils.Requires(getParameters.Length == setParameters.Length - 1, "property", Strings.IndexesOfSetGetMustMatch);
  174. for (int i = 0; i < getParameters.Length; i++) {
  175. ContractUtils.Requires(getParameters[i].ParameterType == setParameters[i].ParameterType, "property", Strings.IndexesOfSetGetMustMatch);
  176. }
  177. } else {
  178. ValidateAccessor(instance, setter, setParameters.RemoveLast(), ref argList);
  179. }
  180. }
  181. if (getter == null && setter == null) {
  182. throw Error.PropertyDoesNotHaveAccessor(property);
  183. }
  184. }
  185. private static void ValidateAccessor(Expression instance, MethodInfo method, ParameterInfo[] indexes, ref ReadOnlyCollection<Expression> arguments) {
  186. ContractUtils.RequiresNotNull(arguments, "arguments");
  187. ValidateMethodInfo(method);
  188. ContractUtils.Requires((method.CallingConvention & CallingConventions.VarArgs) == 0, "method", Strings.AccessorsCannotHaveVarArgs);
  189. if (method.IsStatic) {
  190. ContractUtils.Requires(instance == null, "instance", Strings.OnlyStaticMethodsHaveNullExpr);
  191. } else {
  192. RequiresCanRead(instance, "instance");
  193. ValidateCallInstanceType(instance.Type, method);
  194. }
  195. ValidateAccessorArgumentTypes(method, indexes, ref arguments);
  196. }
  197. private static void ValidateAccessorArgumentTypes(MethodInfo method, ParameterInfo[] indexes, ref ReadOnlyCollection<Expression> arguments) {
  198. if (indexes.Length > 0) {
  199. if (indexes.Length != arguments.Count) {
  200. throw Error.IncorrectNumberOfMethodCallArguments(method);
  201. }
  202. Expression[] newArgs = null;
  203. for (int i = 0, n = indexes.Length; i < n; i++) {
  204. Expression arg = arguments[i];
  205. ParameterInfo pi = indexes[i];
  206. RequiresCanRead(arg, "arguments");
  207. Type pType = pi.ParameterType;
  208. ContractUtils.Requires(!pType.IsByRef, "indexes", Strings.AccessorsCannotHaveByRefArgs);
  209. TypeUtils.ValidateType(pType);
  210. if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
  211. if (TypeUtils.IsSameOrSubclass(typeof(Expression), pType) && TypeUtils.AreAssignable(pType, arg.GetType())) {
  212. arg = Expression.Quote(arg);
  213. } else {
  214. throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
  215. }
  216. }
  217. if (newArgs == null && arg != arguments[i]) {
  218. newArgs = new Expression[arguments.Count];
  219. for (int j = 0; j < i; j++) {
  220. newArgs[j] = arguments[j];
  221. }
  222. }
  223. if (newArgs != null) {
  224. newArgs[i] = arg;
  225. }
  226. }
  227. if (newArgs != null) {
  228. arguments = new ReadOnlyCollection<Expression>(newArgs);
  229. }
  230. } else if (arguments.Count > 0) {
  231. throw Error.IncorrectNumberOfMethodCallArguments(method);
  232. }
  233. }
  234. #endregion
  235. }
  236. }