1 namespace System.Web.Mvc.ExpressionUtil {
3 using System.Collections.Generic;
4 using System.Linq.Expressions;
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.
9 internal sealed class FingerprintingExpressionVisitor : ExpressionVisitor {
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();
16 private FingerprintingExpressionVisitor() { }
18 private T GiveUp<T>(T node) {
19 // We don't understand this node, so just quit.
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();
31 if (visitor._gaveUp) {
32 capturedConstants = null;
36 capturedConstants = visitor._seenConstants;
37 return visitor._currentChain;
41 public override Expression Visit(Expression node) {
43 _currentChain.Elements.Add(null);
47 return base.Visit(node);
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);
57 protected override Expression VisitBlock(BlockExpression node) {
61 protected override CatchBlock VisitCatchBlock(CatchBlock node) {
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);
71 protected override Expression VisitConstant(ConstantExpression node) {
72 if (_gaveUp) { return node; }
74 _seenConstants.Add(node.Value);
75 _currentChain.Elements.Add(new ConstantExpressionFingerprint(node.NodeType, node.Type));
76 return base.VisitConstant(node);
79 protected override Expression VisitDebugInfo(DebugInfoExpression node) {
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);
89 protected override Expression VisitDynamic(DynamicExpression node) {
93 protected override ElementInit VisitElementInit(ElementInit node) {
97 protected override Expression VisitExtension(Expression node) {
101 protected override Expression VisitGoto(GotoExpression node) {
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);
111 protected override Expression VisitInvocation(InvocationExpression node) {
115 protected override Expression VisitLabel(LabelExpression node) {
119 protected override LabelTarget VisitLabelTarget(LabelTarget node) {
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);
129 protected override Expression VisitListInit(ListInitExpression node) {
133 protected override Expression VisitLoop(LoopExpression node) {
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);
143 protected override MemberAssignment VisitMemberAssignment(MemberAssignment node) {
147 protected override MemberBinding VisitMemberBinding(MemberBinding node) {
151 protected override Expression VisitMemberInit(MemberInitExpression node) {
155 protected override MemberListBinding VisitMemberListBinding(MemberListBinding node) {
159 protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
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);
169 protected override Expression VisitNew(NewExpression node) {
173 protected override Expression VisitNewArray(NewArrayExpression node) {
177 protected override Expression VisitParameter(ParameterExpression node) {
178 if (_gaveUp) { return node; }
180 int parameterIndex = _seenParameters.IndexOf(node);
181 if (parameterIndex < 0) {
182 // first time seeing this parameter
183 parameterIndex = _seenParameters.Count;
184 _seenParameters.Add(node);
187 _currentChain.Elements.Add(new ParameterExpressionFingerprint(node.NodeType, node.Type, parameterIndex));
188 return base.VisitParameter(node);
191 protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
195 protected override Expression VisitSwitch(SwitchExpression node) {
199 protected override SwitchCase VisitSwitchCase(SwitchCase node) {
203 protected override Expression VisitTry(TryExpression node) {
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);
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);