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