Merge pull request #249 from pcc/xgetinputfocus
[mono.git] / mcs / class / System.Web.Mvc3 / Mvc / ExpressionUtil / FingerprintingExpressionVisitor.cs
1 namespace System.Web.Mvc.ExpressionUtil {
2     using System;
3     using System.Collections.Generic;
4     using System.Linq.Expressions;
5
6     // This is a visitor which produces a fingerprint of an expression. It doesn't
7     // rewrite the expression in a form which can be compiled and cached.
8
9     internal sealed class FingerprintingExpressionVisitor : ExpressionVisitor {
10
11         private readonly List<object> _seenConstants = new List<object>();
12         private readonly List<ParameterExpression> _seenParameters = new List<ParameterExpression>();
13         private readonly ExpressionFingerprintChain _currentChain = new ExpressionFingerprintChain();
14         private bool _gaveUp;
15
16         private FingerprintingExpressionVisitor() { }
17
18         private T GiveUp<T>(T node) {
19             // We don't understand this node, so just quit.
20
21             _gaveUp = true;
22             return node;
23         }
24
25         // Returns the fingerprint chain + captured constants list for this expression, or null
26         // if the expression couldn't be fingerprinted.
27         public static ExpressionFingerprintChain GetFingerprintChain(Expression expr, out List<object> capturedConstants) {
28             FingerprintingExpressionVisitor visitor = new FingerprintingExpressionVisitor();
29             visitor.Visit(expr);
30
31             if (visitor._gaveUp) {
32                 capturedConstants = null;
33                 return null;
34             }
35             else {
36                 capturedConstants = visitor._seenConstants;
37                 return visitor._currentChain;
38             }
39         }
40
41         public override Expression Visit(Expression node) {
42             if (node == null) {
43                 _currentChain.Elements.Add(null);
44                 return null;
45             }
46             else {
47                 return base.Visit(node);
48             }
49         }
50
51         protected override Expression VisitBinary(BinaryExpression node) {
52             if (_gaveUp) { return node; }
53             _currentChain.Elements.Add(new BinaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
54             return base.VisitBinary(node);
55         }
56
57         protected override Expression VisitBlock(BlockExpression node) {
58             return GiveUp(node);
59         }
60
61         protected override CatchBlock VisitCatchBlock(CatchBlock node) {
62             return GiveUp(node);
63         }
64
65         protected override Expression VisitConditional(ConditionalExpression node) {
66             if (_gaveUp) { return node; }
67             _currentChain.Elements.Add(new ConditionalExpressionFingerprint(node.NodeType, node.Type));
68             return base.VisitConditional(node);
69         }
70
71         protected override Expression VisitConstant(ConstantExpression node) {
72             if (_gaveUp) { return node; }
73
74             _seenConstants.Add(node.Value);
75             _currentChain.Elements.Add(new ConstantExpressionFingerprint(node.NodeType, node.Type));
76             return base.VisitConstant(node);
77         }
78
79         protected override Expression VisitDebugInfo(DebugInfoExpression node) {
80             return GiveUp(node);
81         }
82
83         protected override Expression VisitDefault(DefaultExpression node) {
84             if (_gaveUp) { return node; }
85             _currentChain.Elements.Add(new DefaultExpressionFingerprint(node.NodeType, node.Type));
86             return base.VisitDefault(node);
87         }
88
89         protected override Expression VisitDynamic(DynamicExpression node) {
90             return GiveUp(node);
91         }
92
93         protected override ElementInit VisitElementInit(ElementInit node) {
94             return GiveUp(node);
95         }
96
97         protected override Expression VisitExtension(Expression node) {
98             return GiveUp(node);
99         }
100
101         protected override Expression VisitGoto(GotoExpression node) {
102             return GiveUp(node);
103         }
104
105         protected override Expression VisitIndex(IndexExpression node) {
106             if (_gaveUp) { return node; }
107             _currentChain.Elements.Add(new IndexExpressionFingerprint(node.NodeType, node.Type, node.Indexer));
108             return base.VisitIndex(node);
109         }
110
111         protected override Expression VisitInvocation(InvocationExpression node) {
112             return GiveUp(node);
113         }
114
115         protected override Expression VisitLabel(LabelExpression node) {
116             return GiveUp(node);
117         }
118
119         protected override LabelTarget VisitLabelTarget(LabelTarget node) {
120             return GiveUp(node);
121         }
122
123         protected override Expression VisitLambda<T>(Expression<T> node) {
124             if (_gaveUp) { return node; }
125             _currentChain.Elements.Add(new LambdaExpressionFingerprint(node.NodeType, node.Type));
126             return base.VisitLambda<T>(node);
127         }
128
129         protected override Expression VisitListInit(ListInitExpression node) {
130             return GiveUp(node);
131         }
132
133         protected override Expression VisitLoop(LoopExpression node) {
134             return GiveUp(node);
135         }
136
137         protected override Expression VisitMember(MemberExpression node) {
138             if (_gaveUp) { return node; }
139             _currentChain.Elements.Add(new MemberExpressionFingerprint(node.NodeType, node.Type, node.Member));
140             return base.VisitMember(node);
141         }
142
143         protected override MemberAssignment VisitMemberAssignment(MemberAssignment node) {
144             return GiveUp(node);
145         }
146
147         protected override MemberBinding VisitMemberBinding(MemberBinding node) {
148             return GiveUp(node);
149         }
150
151         protected override Expression VisitMemberInit(MemberInitExpression node) {
152             return GiveUp(node);
153         }
154
155         protected override MemberListBinding VisitMemberListBinding(MemberListBinding node) {
156             return GiveUp(node);
157         }
158
159         protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
160             return GiveUp(node);
161         }
162
163         protected override Expression VisitMethodCall(MethodCallExpression node) {
164             if (_gaveUp) { return node; }
165             _currentChain.Elements.Add(new MethodCallExpressionFingerprint(node.NodeType, node.Type, node.Method));
166             return base.VisitMethodCall(node);
167         }
168
169         protected override Expression VisitNew(NewExpression node) {
170             return GiveUp(node);
171         }
172
173         protected override Expression VisitNewArray(NewArrayExpression node) {
174             return GiveUp(node);
175         }
176
177         protected override Expression VisitParameter(ParameterExpression node) {
178             if (_gaveUp) { return node; }
179
180             int parameterIndex = _seenParameters.IndexOf(node);
181             if (parameterIndex < 0) {
182                 // first time seeing this parameter
183                 parameterIndex = _seenParameters.Count;
184                 _seenParameters.Add(node);
185             }
186
187             _currentChain.Elements.Add(new ParameterExpressionFingerprint(node.NodeType, node.Type, parameterIndex));
188             return base.VisitParameter(node);
189         }
190
191         protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
192             return GiveUp(node);
193         }
194
195         protected override Expression VisitSwitch(SwitchExpression node) {
196             return GiveUp(node);
197         }
198
199         protected override SwitchCase VisitSwitchCase(SwitchCase node) {
200             return GiveUp(node);
201         }
202
203         protected override Expression VisitTry(TryExpression node) {
204             return GiveUp(node);
205         }
206
207         protected override Expression VisitTypeBinary(TypeBinaryExpression node) {
208             if (_gaveUp) { return node; }
209             _currentChain.Elements.Add(new TypeBinaryExpressionFingerprint(node.NodeType, node.Type, node.TypeOperand));
210             return base.VisitTypeBinary(node);
211         }
212
213         protected override Expression VisitUnary(UnaryExpression node) {
214             if (_gaveUp) { return node; }
215             _currentChain.Elements.Add(new UnaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
216             return base.VisitUnary(node);
217         }
218
219     }
220 }