PageRenderTime 66ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting.Core/Ast/ExpressionVisitor.cs

https://bitbucket.org/stefanrusek/xronos
C# | 790 lines | 433 code | 65 blank | 292 comment | 170 complexity | c9f1eec4646560fa3c357cd3fc45844c MD5 | raw file
  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.ObjectModel;
  17. using System.Diagnostics;
  18. #if CODEPLEX_40
  19. using System.Dynamic.Utils;
  20. #else
  21. using Microsoft.Scripting.Utils;
  22. #endif
  23. using System.Runtime.CompilerServices;
  24. #if !CODEPLEX_40
  25. using Microsoft.Runtime.CompilerServices;
  26. #endif
  27. #if CODEPLEX_40
  28. namespace System.Linq.Expressions {
  29. #else
  30. namespace Microsoft.Linq.Expressions {
  31. #endif
  32. /// <summary>
  33. /// Represents a visitor or rewriter for expression trees.
  34. /// </summary>
  35. /// <remarks>
  36. /// This class is designed to be inherited to create more specialized
  37. /// classes whose functionality requires traversing, examining or copying
  38. /// an expression tree.
  39. /// </remarks>
  40. public abstract class ExpressionVisitor {
  41. /// <summary>
  42. /// Initializes a new instance of <see cref="ExpressionVisitor"/>.
  43. /// </summary>
  44. protected ExpressionVisitor() {
  45. }
  46. /// <summary>
  47. /// Dispatches the expression to one of the more specialized visit methods in this class.
  48. /// </summary>
  49. /// <param name="node">The expression to visit.</param>
  50. /// <returns>The modified expression, if it or any subexpression was modified;
  51. /// otherwise, returns the original expression.</returns>
  52. public virtual Expression Visit(Expression node) {
  53. if (node != null) {
  54. return node.Accept(this);
  55. }
  56. return null;
  57. }
  58. /// <summary>
  59. /// Dispatches the list of expressions to one of the more specialized visit methods in this class.
  60. /// </summary>
  61. /// <param name="nodes">The expressions to visit.</param>
  62. /// <returns>The modified expression list, if any of the elements were modified;
  63. /// otherwise, returns the original expression list.</returns>
  64. protected ReadOnlyCollection<Expression> Visit(ReadOnlyCollection<Expression> nodes) {
  65. Expression[] newNodes = null;
  66. for (int i = 0, n = nodes.Count; i < n; i++) {
  67. Expression node = Visit(nodes[i]);
  68. if (newNodes != null) {
  69. newNodes[i] = node;
  70. } else if (!object.ReferenceEquals(node, nodes[i])) {
  71. newNodes = new Expression[n];
  72. for (int j = 0; j < i; j++) {
  73. newNodes[j] = nodes[j];
  74. }
  75. newNodes[i] = node;
  76. }
  77. }
  78. if (newNodes == null) {
  79. return nodes;
  80. }
  81. return new TrueReadOnlyCollection<Expression>(newNodes);
  82. }
  83. internal Expression[] VisitArguments(IArgumentProvider nodes) {
  84. Expression[] newNodes = null;
  85. for (int i = 0, n = nodes.ArgumentCount; i < n; i++) {
  86. Expression curNode = nodes.GetArgument(i);
  87. Expression node = Visit(curNode);
  88. if (newNodes != null) {
  89. newNodes[i] = node;
  90. } else if (!object.ReferenceEquals(node, curNode)) {
  91. newNodes = new Expression[n];
  92. for (int j = 0; j < i; j++) {
  93. newNodes[j] = nodes.GetArgument(j);
  94. }
  95. newNodes[i] = node;
  96. }
  97. }
  98. return newNodes;
  99. }
  100. /// <summary>
  101. /// Visits all nodes in the collection using a specified element visitor.
  102. /// </summary>
  103. /// <typeparam name="T">The type of the nodes.</typeparam>
  104. /// <param name="nodes">The nodes to visit.</param>
  105. /// <param name="elementVisitor">A delegate that visits a single element,
  106. /// optionally replacing it with a new element.</param>
  107. /// <returns>The modified node list, if any of the elements were modified;
  108. /// otherwise, returns the original node list.</returns>
  109. protected static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor) {
  110. T[] newNodes = null;
  111. for (int i = 0, n = nodes.Count; i < n; i++) {
  112. T node = elementVisitor(nodes[i]);
  113. if (newNodes != null) {
  114. newNodes[i] = node;
  115. } else if (!object.ReferenceEquals(node, nodes[i])) {
  116. newNodes = new T[n];
  117. for (int j = 0; j < i; j++) {
  118. newNodes[j] = nodes[j];
  119. }
  120. newNodes[i] = node;
  121. }
  122. }
  123. if (newNodes == null) {
  124. return nodes;
  125. }
  126. return new TrueReadOnlyCollection<T>(newNodes);
  127. }
  128. /// <summary>
  129. /// Visits an expression, casting the result back to the original expression type.
  130. /// </summary>
  131. /// <typeparam name="T">The type of the expression.</typeparam>
  132. /// <param name="node">The expression to visit.</param>
  133. /// <param name="callerName">The name of the calling method; used to report to report a better error message.</param>
  134. /// <returns>The modified expression, if it or any subexpression was modified;
  135. /// otherwise, returns the original expression.</returns>
  136. /// <exception cref="InvalidOperationException">The visit method for this node returned a different type.</exception>
  137. protected T VisitAndConvert<T>(T node, string callerName) where T : Expression {
  138. if (node == null) {
  139. return null;
  140. }
  141. node = Visit(node) as T;
  142. if (node == null) {
  143. throw Error.MustRewriteToSameNode(callerName, typeof(T), callerName);
  144. }
  145. return node;
  146. }
  147. /// <summary>
  148. /// Visits an expression, casting the result back to the original expression type.
  149. /// </summary>
  150. /// <typeparam name="T">The type of the expression.</typeparam>
  151. /// <param name="nodes">The expression to visit.</param>
  152. /// <param name="callerName">The name of the calling method; used to report to report a better error message.</param>
  153. /// <returns>The modified expression, if it or any subexpression was modified;
  154. /// otherwise, returns the original expression.</returns>
  155. /// <exception cref="InvalidOperationException">The visit method for this node returned a different type.</exception>
  156. protected ReadOnlyCollection<T> VisitAndConvert<T>(ReadOnlyCollection<T> nodes, string callerName) where T : Expression {
  157. T[] newNodes = null;
  158. for (int i = 0, n = nodes.Count; i < n; i++) {
  159. T node = Visit(nodes[i]) as T;
  160. if (node == null) {
  161. throw Error.MustRewriteToSameNode(callerName, typeof(T), callerName);
  162. }
  163. if (newNodes != null) {
  164. newNodes[i] = node;
  165. } else if (!object.ReferenceEquals(node, nodes[i])) {
  166. newNodes = new T[n];
  167. for (int j = 0; j < i; j++) {
  168. newNodes[j] = nodes[j];
  169. }
  170. newNodes[i] = node;
  171. }
  172. }
  173. if (newNodes == null) {
  174. return nodes;
  175. }
  176. return new TrueReadOnlyCollection<T>(newNodes);
  177. }
  178. /// <summary>
  179. /// Visits the children of the <see cref="BinaryExpression" />.
  180. /// </summary>
  181. /// <param name="node">The expression to visit.</param>
  182. /// <returns>The modified expression, if it or any subexpression was modified;
  183. /// otherwise, returns the original expression.</returns>
  184. protected internal virtual Expression VisitBinary(BinaryExpression node) {
  185. // Walk children in evaluation order: left, conversion, right
  186. Expression l = Visit(node.Left);
  187. LambdaExpression c = VisitAndConvert(node.Conversion, "VisitBinary");
  188. Expression r = Visit(node.Right);
  189. if (l == node.Left && r == node.Right && c == node.Conversion) {
  190. return node;
  191. }
  192. if (node.IsReferenceComparison) {
  193. if (node.NodeType == ExpressionType.Equal) {
  194. return Expression.ReferenceEqual(l, r);
  195. } else {
  196. return Expression.ReferenceNotEqual(l, r);
  197. }
  198. }
  199. var result = Expression.MakeBinary(node.NodeType, l, r, node.IsLiftedToNull, node.Method, c);
  200. ValidateBinary(node, result);
  201. return result;
  202. }
  203. /// <summary>
  204. /// Visits the children of the <see cref="BlockExpression" />.
  205. /// </summary>
  206. /// <param name="node">The expression to visit.</param>
  207. /// <returns>The modified expression, if it or any subexpression was modified;
  208. /// otherwise, returns the original expression.</returns>
  209. protected internal virtual Expression VisitBlock(BlockExpression node) {
  210. int count = node.ExpressionCount;
  211. Expression[] nodes = null;
  212. for (int i = 0; i < count; i++) {
  213. Expression oldNode = node.GetExpression(i);
  214. Expression newNode = Visit(oldNode);
  215. if (oldNode != newNode) {
  216. if (nodes == null) {
  217. nodes = new Expression[count];
  218. }
  219. nodes[i] = newNode;
  220. }
  221. }
  222. var v = VisitAndConvert(node.Variables, "VisitBlock");
  223. if (v == node.Variables && nodes == null) {
  224. return node;
  225. } else {
  226. for (int i = 0; i < count; i++) {
  227. if (nodes[i] == null) {
  228. nodes[i] = node.GetExpression(i);
  229. }
  230. }
  231. }
  232. return node.Rewrite(v, nodes);
  233. }
  234. /// <summary>
  235. /// Visits the children of the <see cref="ConditionalExpression" />.
  236. /// </summary>
  237. /// <param name="node">The expression to visit.</param>
  238. /// <returns>The modified expression, if it or any subexpression was modified;
  239. /// otherwise, returns the original expression.</returns>
  240. protected internal virtual Expression VisitConditional(ConditionalExpression node) {
  241. Expression t = Visit(node.Test);
  242. Expression l = Visit(node.IfTrue);
  243. Expression r = Visit(node.IfFalse);
  244. if (t == node.Test && l == node.IfTrue && r == node.IfFalse) {
  245. return node;
  246. }
  247. return Expression.Condition(t, l, r, node.Type);
  248. }
  249. /// <summary>
  250. /// Visits the <see cref="ConstantExpression" />.
  251. /// </summary>
  252. /// <param name="node">The expression to visit.</param>
  253. /// <returns>The modified expression, if it or any subexpression was modified;
  254. /// otherwise, returns the original expression.</returns>
  255. protected internal virtual Expression VisitConstant(ConstantExpression node) {
  256. return node;
  257. }
  258. /// <summary>
  259. /// Visits the <see cref="DebugInfoExpression" />.
  260. /// </summary>
  261. /// <param name="node">The expression to visit.</param>
  262. /// <returns>The modified expression, if it or any subexpression was modified;
  263. /// otherwise, returns the original expression.</returns>
  264. protected internal virtual Expression VisitDebugInfo(DebugInfoExpression node) {
  265. return node;
  266. }
  267. /// <summary>
  268. /// Visits the children of the <see cref="DynamicExpression" />.
  269. /// </summary>
  270. /// <param name="node">The expression to visit.</param>
  271. /// <returns>The modified expression, if it or any subexpression was modified;
  272. /// otherwise, returns the original expression.</returns>
  273. protected internal virtual Expression VisitDynamic(DynamicExpression node) {
  274. Expression[] a = VisitArguments((IArgumentProvider)node);
  275. if (a == null) {
  276. return node;
  277. }
  278. return node.Rewrite(a);
  279. }
  280. /// <summary>
  281. /// Visits the <see cref="DefaultExpression" />.
  282. /// </summary>
  283. /// <param name="node">The expression to visit.</param>
  284. /// <returns>The modified expression, if it or any subexpression was modified;
  285. /// otherwise, returns the original expression.</returns>
  286. protected internal virtual Expression VisitDefault(DefaultExpression node) {
  287. return node;
  288. }
  289. /// <summary>
  290. /// Visits the children of the extension expression.
  291. /// </summary>
  292. /// <param name="node">The expression to visit.</param>
  293. /// <returns>The modified expression, if it or any subexpression was modified;
  294. /// otherwise, returns the original expression.</returns>
  295. /// <remarks>
  296. /// This can be overridden to visit or rewrite specific extension nodes.
  297. /// If it is not overridden, this method will call <see cref="Expression.VisitChildren" />,
  298. /// which gives the node a chance to walk its children. By default,
  299. /// <see cref="Expression.VisitChildren" /> will try to reduce the node.
  300. /// </remarks>
  301. protected internal virtual Expression VisitExtension(Expression node) {
  302. return node.VisitChildren(this.Visit);
  303. }
  304. /// <summary>
  305. /// Visits the children of the <see cref="GotoExpression" />.
  306. /// </summary>
  307. /// <param name="node">The expression to visit.</param>
  308. /// <returns>The modified expression, if it or any subexpression was modified;
  309. /// otherwise, returns the original expression.</returns>
  310. protected internal virtual Expression VisitGoto(GotoExpression node) {
  311. LabelTarget t = VisitLabelTarget(node.Target);
  312. Expression v = Visit(node.Value);
  313. if (t == node.Target && v == node.Value) {
  314. return node;
  315. }
  316. return Expression.MakeGoto(node.Kind, t, v, node.Type);
  317. }
  318. /// <summary>
  319. /// Visits the children of the <see cref="InvocationExpression" />.
  320. /// </summary>
  321. /// <param name="node">The expression to visit.</param>
  322. /// <returns>The modified expression, if it or any subexpression was modified;
  323. /// otherwise, returns the original expression.</returns>
  324. protected internal virtual Expression VisitInvocation(InvocationExpression node) {
  325. Expression e = Visit(node.Expression);
  326. Expression[] a = VisitArguments(node);
  327. if (e == node.Expression && a == null) {
  328. return node;
  329. }
  330. return node.Rewrite(e, a);
  331. }
  332. /// <summary>
  333. /// Visits the <see cref="LabelTarget" />.
  334. /// </summary>
  335. /// <param name="node">The expression to visit.</param>
  336. /// <returns>The modified expression, if it or any subexpression was modified;
  337. /// otherwise, returns the original expression.</returns>
  338. protected virtual LabelTarget VisitLabelTarget(LabelTarget node) {
  339. return node;
  340. }
  341. /// <summary>
  342. /// Visits the children of the <see cref="LabelExpression" />.
  343. /// </summary>
  344. /// <param name="node">The expression to visit.</param>
  345. /// <returns>The modified expression, if it or any subexpression was modified;
  346. /// otherwise, returns the original expression.</returns>
  347. protected internal virtual Expression VisitLabel(LabelExpression node) {
  348. LabelTarget l = VisitLabelTarget(node.Target);
  349. Expression d = Visit(node.DefaultValue);
  350. if (l == node.Target && d == node.DefaultValue) {
  351. return node;
  352. }
  353. return Expression.Label(l, d);
  354. }
  355. /// <summary>
  356. /// Visits the children of the <see cref="Expression&lt;T&gt;" />.
  357. /// </summary>
  358. /// <typeparam name="T">The type of the delegate.</typeparam>
  359. /// <param name="node">The expression to visit.</param>
  360. /// <returns>The modified expression, if it or any subexpression was modified;
  361. /// otherwise, returns the original expression.</returns>
  362. protected internal virtual Expression VisitLambda<T>(Expression<T> node) {
  363. Expression b = Visit(node.Body);
  364. var p = VisitAndConvert(node.Parameters, "VisitLambda");
  365. if (b == node.Body && p == node.Parameters) {
  366. return node;
  367. }
  368. return Expression.Lambda<T>(b, node.Name, p);
  369. }
  370. /// <summary>
  371. /// Visits the children of the <see cref="LoopExpression" />.
  372. /// </summary>
  373. /// <param name="node">The expression to visit.</param>
  374. /// <returns>The modified expression, if it or any subexpression was modified;
  375. /// otherwise, returns the original expression.</returns>
  376. protected internal virtual Expression VisitLoop(LoopExpression node) {
  377. LabelTarget @break = VisitLabelTarget(node.BreakLabel);
  378. LabelTarget @continue = VisitLabelTarget(node.ContinueLabel);
  379. Expression b = Visit(node.Body);
  380. if (@break == node.BreakLabel &&
  381. @continue == node.ContinueLabel &&
  382. b == node.Body) {
  383. return node;
  384. }
  385. return Expression.Loop(b, @break, @continue);
  386. }
  387. /// <summary>
  388. /// Visits the children of the <see cref="MemberExpression" />.
  389. /// </summary>
  390. /// <param name="node">The expression to visit.</param>
  391. /// <returns>The modified expression, if it or any subexpression was modified;
  392. /// otherwise, returns the original expression.</returns>
  393. protected internal virtual Expression VisitMember(MemberExpression node) {
  394. Expression e = Visit(node.Expression);
  395. if (e == node.Expression) {
  396. return node;
  397. }
  398. return Expression.MakeMemberAccess(e, node.Member);
  399. }
  400. /// <summary>
  401. /// Visits the children of the <see cref="IndexExpression" />.
  402. /// </summary>
  403. /// <param name="node">The expression to visit.</param>
  404. /// <returns>The modified expression, if it or any subexpression was modified;
  405. /// otherwise, returns the original expression.</returns>
  406. protected internal virtual Expression VisitIndex(IndexExpression node) {
  407. Expression o = Visit(node.Object);
  408. Expression[] a = VisitArguments(node);
  409. if (o == node.Object && a == null) {
  410. return node;
  411. }
  412. return node.Rewrite(o, a);
  413. }
  414. /// <summary>
  415. /// Visits the children of the <see cref="MethodCallExpression" />.
  416. /// </summary>
  417. /// <param name="node">The expression to visit.</param>
  418. /// <returns>The modified expression, if it or any subexpression was modified;
  419. /// otherwise, returns the original expression.</returns>
  420. protected internal virtual Expression VisitMethodCall(MethodCallExpression node) {
  421. Expression o = Visit(node.Object);
  422. Expression[] a = VisitArguments((IArgumentProvider)node);
  423. if (o == node.Object && a == null) {
  424. return node;
  425. }
  426. return node.Rewrite(o, a);
  427. }
  428. /// <summary>
  429. /// Visits the children of the <see cref="NewArrayExpression" />.
  430. /// </summary>
  431. /// <param name="node">The expression to visit.</param>
  432. /// <returns>The modified expression, if it or any subexpression was modified;
  433. /// otherwise, returns the original expression.</returns>
  434. protected internal virtual Expression VisitNewArray(NewArrayExpression node) {
  435. ReadOnlyCollection<Expression> e = Visit(node.Expressions);
  436. if (e == node.Expressions) {
  437. return node;
  438. }
  439. if (node.NodeType == ExpressionType.NewArrayInit) {
  440. return Expression.NewArrayInit(node.Type.GetElementType(), e);
  441. }
  442. return Expression.NewArrayBounds(node.Type.GetElementType(), e);
  443. }
  444. /// <summary>
  445. /// Visits the children of the <see cref="NewExpression" />.
  446. /// </summary>
  447. /// <param name="node">The expression to visit.</param>
  448. /// <returns>The modified expression, if it or any subexpression was modified;
  449. /// otherwise, returns the original expression.</returns>
  450. protected internal virtual Expression VisitNew(NewExpression node) {
  451. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  452. if (a == node.Arguments) {
  453. return node;
  454. }
  455. if (node.Members != null) {
  456. return Expression.New(node.Constructor, a, node.Members);
  457. }
  458. return Expression.New(node.Constructor, a);
  459. }
  460. /// <summary>
  461. /// Visits the <see cref="ParameterExpression" />.
  462. /// </summary>
  463. /// <param name="node">The expression to visit.</param>
  464. /// <returns>The modified expression, if it or any subexpression was modified;
  465. /// otherwise, returns the original expression.</returns>
  466. protected internal virtual Expression VisitParameter(ParameterExpression node) {
  467. return node;
  468. }
  469. /// <summary>
  470. /// Visits the children of the <see cref="RuntimeVariablesExpression" />.
  471. /// </summary>
  472. /// <param name="node">The expression to visit.</param>
  473. /// <returns>The modified expression, if it or any subexpression was modified;
  474. /// otherwise, returns the original expression.</returns>
  475. protected internal virtual Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
  476. var v = VisitAndConvert(node.Variables, "VisitRuntimeVariables");
  477. if (v == node.Variables) {
  478. return node;
  479. }
  480. return Expression.RuntimeVariables(v);
  481. }
  482. /// <summary>
  483. /// Visits the children of the <see cref="SwitchCase" />.
  484. /// </summary>
  485. /// <param name="node">The expression to visit.</param>
  486. /// <returns>The modified expression, if it or any subexpression was modified;
  487. /// otherwise, returns the original expression.</returns>
  488. protected virtual SwitchCase VisitSwitchCase(SwitchCase node) {
  489. ReadOnlyCollection<Expression> t = Visit(node.TestValues);
  490. Expression b = Visit(node.Body);
  491. if (t == node.TestValues && b == node.Body) {
  492. return node;
  493. }
  494. return Expression.SwitchCase(b, t);
  495. }
  496. /// <summary>
  497. /// Visits the children of the <see cref="SwitchExpression" />.
  498. /// </summary>
  499. /// <param name="node">The expression to visit.</param>
  500. /// <returns>The modified expression, if it or any subexpression was modified;
  501. /// otherwise, returns the original expression.</returns>
  502. protected internal virtual Expression VisitSwitch(SwitchExpression node) {
  503. Expression s = Visit(node.SwitchValue);
  504. ReadOnlyCollection<SwitchCase> c = Visit(node.Cases, VisitSwitchCase);
  505. Expression d = Visit(node.DefaultBody);
  506. if (s == node.SwitchValue && c == node.Cases && d == node.DefaultBody) {
  507. return node;
  508. }
  509. var result = Expression.Switch(node.Type, s, d, node.Comparison, c);
  510. ValidateSwitch(node, result);
  511. return result;
  512. }
  513. /// <summary>
  514. /// Visits the children of the <see cref="CatchBlock" />.
  515. /// </summary>
  516. /// <param name="node">The expression to visit.</param>
  517. /// <returns>The modified expression, if it or any subexpression was modified;
  518. /// otherwise, returns the original expression.</returns>
  519. protected virtual CatchBlock VisitCatchBlock(CatchBlock node) {
  520. ParameterExpression v = VisitAndConvert(node.Variable, "VisitCatchBlock");
  521. Expression f = Visit(node.Filter);
  522. Expression b = Visit(node.Body);
  523. if (v == node.Variable && b == node.Body && f == node.Filter) {
  524. return node;
  525. }
  526. return Expression.MakeCatchBlock(node.Test, v, b, f);
  527. }
  528. /// <summary>
  529. /// Visits the children of the <see cref="TryExpression" />.
  530. /// </summary>
  531. /// <param name="node">The expression to visit.</param>
  532. /// <returns>The modified expression, if it or any subexpression was modified;
  533. /// otherwise, returns the original expression.</returns>
  534. protected internal virtual Expression VisitTry(TryExpression node) {
  535. Expression b = Visit(node.Body);
  536. ReadOnlyCollection<CatchBlock> h = Visit(node.Handlers, VisitCatchBlock);
  537. Expression y = Visit(node.Finally);
  538. Expression f = Visit(node.Fault);
  539. if (b == node.Body &&
  540. h == node.Handlers &&
  541. y == node.Finally &&
  542. f == node.Fault) {
  543. return node;
  544. }
  545. return Expression.MakeTry(node.Type, b, y, f, h);
  546. }
  547. /// <summary>
  548. /// Visits the children of the <see cref="TypeBinaryExpression" />.
  549. /// </summary>
  550. /// <param name="node">The expression to visit.</param>
  551. /// <returns>The modified expression, if it or any subexpression was modified;
  552. /// otherwise, returns the original expression.</returns>
  553. protected internal virtual Expression VisitTypeBinary(TypeBinaryExpression node) {
  554. Expression e = Visit(node.Expression);
  555. if (e == node.Expression) {
  556. return node;
  557. }
  558. if (node.NodeType == ExpressionType.TypeIs) {
  559. return Expression.TypeIs(e, node.TypeOperand);
  560. }
  561. return Expression.TypeEqual(e, node.TypeOperand);
  562. }
  563. /// <summary>
  564. /// Visits the children of the <see cref="UnaryExpression" />.
  565. /// </summary>
  566. /// <param name="node">The expression to visit.</param>
  567. /// <returns>The modified expression, if it or any subexpression was modified;
  568. /// otherwise, returns the original expression.</returns>
  569. protected internal virtual Expression VisitUnary(UnaryExpression node) {
  570. Expression o = Visit(node.Operand);
  571. if (o == node.Operand) {
  572. return node;
  573. }
  574. var result = Expression.MakeUnary(node.NodeType, o, node.Type, node.Method);
  575. ValidateUnary(node, result);
  576. return result;
  577. }
  578. /// <summary>
  579. /// Visits the children of the <see cref="MemberInitExpression" />.
  580. /// </summary>
  581. /// <param name="node">The expression to visit.</param>
  582. /// <returns>The modified expression, if it or any subexpression was modified;
  583. /// otherwise, returns the original expression.</returns>
  584. protected internal virtual Expression VisitMemberInit(MemberInitExpression node) {
  585. NewExpression n = VisitAndConvert(node.NewExpression, "VisitMemberInit");
  586. ReadOnlyCollection<MemberBinding> bindings = Visit(node.Bindings, VisitMemberBinding);
  587. if (n == node.NewExpression && bindings == node.Bindings) {
  588. return node;
  589. }
  590. return Expression.MemberInit(n, bindings);
  591. }
  592. /// <summary>
  593. /// Visits the children of the <see cref="ListInitExpression" />.
  594. /// </summary>
  595. /// <param name="node">The expression to visit.</param>
  596. /// <returns>The modified expression, if it or any subexpression was modified;
  597. /// otherwise, returns the original expression.</returns>
  598. protected internal virtual Expression VisitListInit(ListInitExpression node) {
  599. NewExpression n = VisitAndConvert(node.NewExpression, "VisitListInit");
  600. ReadOnlyCollection<ElementInit> initializers = Visit(node.Initializers, VisitElementInit);
  601. if (n == node.NewExpression && initializers == node.Initializers) {
  602. return node;
  603. }
  604. return Expression.ListInit(n, initializers);
  605. }
  606. /// <summary>
  607. /// Visits the children of the <see cref="ElementInit" />.
  608. /// </summary>
  609. /// <param name="node">The expression to visit.</param>
  610. /// <returns>The modified expression, if it or any subexpression was modified;
  611. /// otherwise, returns the original expression.</returns>
  612. protected virtual ElementInit VisitElementInit(ElementInit node) {
  613. ReadOnlyCollection<Expression> arguments = Visit(node.Arguments);
  614. if (arguments == node.Arguments) {
  615. return node;
  616. }
  617. return Expression.ElementInit(node.AddMethod, arguments);
  618. }
  619. /// <summary>
  620. /// Visits the children of the <see cref="MemberBinding" />.
  621. /// </summary>
  622. /// <param name="node">The expression to visit.</param>
  623. /// <returns>The modified expression, if it or any subexpression was modified;
  624. /// otherwise, returns the original expression.</returns>
  625. protected virtual MemberBinding VisitMemberBinding(MemberBinding node) {
  626. switch (node.BindingType) {
  627. case MemberBindingType.Assignment:
  628. return VisitMemberAssignment((MemberAssignment)node);
  629. case MemberBindingType.MemberBinding:
  630. return VisitMemberMemberBinding((MemberMemberBinding)node);
  631. case MemberBindingType.ListBinding:
  632. return VisitMemberListBinding((MemberListBinding)node);
  633. default:
  634. throw Error.UnhandledBindingType(node.BindingType);
  635. }
  636. }
  637. /// <summary>
  638. /// Visits the children of the <see cref="MemberAssignment" />.
  639. /// </summary>
  640. /// <param name="node">The expression to visit.</param>
  641. /// <returns>The modified expression, if it or any subexpression was modified;
  642. /// otherwise, returns the original expression.</returns>
  643. protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment node) {
  644. Expression e = Visit(node.Expression);
  645. if (e == node.Expression) {
  646. return node;
  647. }
  648. return Expression.Bind(node.Member, e);
  649. }
  650. /// <summary>
  651. /// Visits the children of the <see cref="MemberMemberBinding" />.
  652. /// </summary>
  653. /// <param name="node">The expression to visit.</param>
  654. /// <returns>The modified expression, if it or any subexpression was modified;
  655. /// otherwise, returns the original expression.</returns>
  656. protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
  657. ReadOnlyCollection<MemberBinding> bindings = Visit(node.Bindings, VisitMemberBinding);
  658. if (bindings == node.Bindings) {
  659. return node;
  660. }
  661. return Expression.MemberBind(node.Member, bindings);
  662. }
  663. /// <summary>
  664. /// Visits the children of the <see cref="MemberListBinding" />.
  665. /// </summary>
  666. /// <param name="node">The expression to visit.</param>
  667. /// <returns>The modified expression, if it or any subexpression was modified;
  668. /// otherwise, returns the original expression.</returns>
  669. protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding node) {
  670. ReadOnlyCollection<ElementInit> initializers = Visit(node.Initializers, VisitElementInit);
  671. if (initializers == node.Initializers) {
  672. return node;
  673. }
  674. return Expression.ListBind(node.Member, initializers);
  675. }
  676. //
  677. // Prevent some common cases of invalid rewrites.
  678. //
  679. // Essentially, we don't want the rewritten node to be semantically
  680. // bound by the factory, which may do the wrong thing. Instead we
  681. // require derived classes to be explicit about what they want to do if
  682. // types change.
  683. //
  684. private static void ValidateUnary(UnaryExpression before, UnaryExpression after) {
  685. if (before.Method == null) {
  686. if (after.Method != null) {
  687. throw Error.MustRewriteWithoutMethod(after.Method, "VisitUnary");
  688. }
  689. ValidateChildType(before.Operand.Type, after.Operand.Type, "VisitUnary");
  690. }
  691. }
  692. private static void ValidateBinary(BinaryExpression before, BinaryExpression after) {
  693. if (before.Method == null) {
  694. if (after.Method != null) {
  695. throw Error.MustRewriteWithoutMethod(after.Method, "VisitBinary");
  696. }
  697. ValidateChildType(before.Left.Type, after.Left.Type, "VisitBinary");
  698. ValidateChildType(before.Right.Type, after.Right.Type, "VisitBinary");
  699. }
  700. }
  701. // We wouldn't need this if switch didn't infer the method.
  702. private static void ValidateSwitch(SwitchExpression before, SwitchExpression after) {
  703. // If we did not have a method, we don't want to bind to one,
  704. // it might not be the right thing.
  705. if (before.Comparison == null && after.Comparison != null) {
  706. throw Error.MustRewriteWithoutMethod(after.Comparison, "VisitSwitch");
  707. }
  708. }
  709. // Value types must stay as the same type, otherwise it's now a
  710. // different operation, e.g. adding two doubles vs adding two ints.
  711. private static void ValidateChildType(Type before, Type after, string methodName) {
  712. if (before.IsValueType) {
  713. if (before == after) {
  714. // types are the same value type
  715. return;
  716. }
  717. } else if (!after.IsValueType) {
  718. // both are reference types
  719. return;
  720. }
  721. // Otherwise, it's an invalid type change.
  722. throw Error.MustRewriteChildToSameType(before, after, methodName);
  723. }
  724. }
  725. }