a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
221 lines
7.9 KiB
C#
221 lines
7.9 KiB
C#
namespace System.Web.Mvc.ExpressionUtil {
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
|
|
// This is a visitor which produces a fingerprint of an expression. It doesn't
|
|
// rewrite the expression in a form which can be compiled and cached.
|
|
|
|
internal sealed class FingerprintingExpressionVisitor : ExpressionVisitor {
|
|
|
|
private readonly List<object> _seenConstants = new List<object>();
|
|
private readonly List<ParameterExpression> _seenParameters = new List<ParameterExpression>();
|
|
private readonly ExpressionFingerprintChain _currentChain = new ExpressionFingerprintChain();
|
|
private bool _gaveUp;
|
|
|
|
private FingerprintingExpressionVisitor() { }
|
|
|
|
private T GiveUp<T>(T node) {
|
|
// We don't understand this node, so just quit.
|
|
|
|
_gaveUp = true;
|
|
return node;
|
|
}
|
|
|
|
// Returns the fingerprint chain + captured constants list for this expression, or null
|
|
// if the expression couldn't be fingerprinted.
|
|
public static ExpressionFingerprintChain GetFingerprintChain(Expression expr, out List<object> capturedConstants) {
|
|
FingerprintingExpressionVisitor visitor = new FingerprintingExpressionVisitor();
|
|
visitor.Visit(expr);
|
|
|
|
if (visitor._gaveUp) {
|
|
capturedConstants = null;
|
|
return null;
|
|
}
|
|
else {
|
|
capturedConstants = visitor._seenConstants;
|
|
return visitor._currentChain;
|
|
}
|
|
}
|
|
|
|
public override Expression Visit(Expression node) {
|
|
if (node == null) {
|
|
_currentChain.Elements.Add(null);
|
|
return null;
|
|
}
|
|
else {
|
|
return base.Visit(node);
|
|
}
|
|
}
|
|
|
|
protected override Expression VisitBinary(BinaryExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new BinaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
|
|
return base.VisitBinary(node);
|
|
}
|
|
|
|
protected override Expression VisitBlock(BlockExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override CatchBlock VisitCatchBlock(CatchBlock node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitConditional(ConditionalExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new ConditionalExpressionFingerprint(node.NodeType, node.Type));
|
|
return base.VisitConditional(node);
|
|
}
|
|
|
|
protected override Expression VisitConstant(ConstantExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
|
|
_seenConstants.Add(node.Value);
|
|
_currentChain.Elements.Add(new ConstantExpressionFingerprint(node.NodeType, node.Type));
|
|
return base.VisitConstant(node);
|
|
}
|
|
|
|
protected override Expression VisitDebugInfo(DebugInfoExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitDefault(DefaultExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new DefaultExpressionFingerprint(node.NodeType, node.Type));
|
|
return base.VisitDefault(node);
|
|
}
|
|
|
|
protected override Expression VisitDynamic(DynamicExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override ElementInit VisitElementInit(ElementInit node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitExtension(Expression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitGoto(GotoExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitIndex(IndexExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new IndexExpressionFingerprint(node.NodeType, node.Type, node.Indexer));
|
|
return base.VisitIndex(node);
|
|
}
|
|
|
|
protected override Expression VisitInvocation(InvocationExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitLabel(LabelExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override LabelTarget VisitLabelTarget(LabelTarget node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitLambda<T>(Expression<T> node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new LambdaExpressionFingerprint(node.NodeType, node.Type));
|
|
return base.VisitLambda<T>(node);
|
|
}
|
|
|
|
protected override Expression VisitListInit(ListInitExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitLoop(LoopExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitMember(MemberExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new MemberExpressionFingerprint(node.NodeType, node.Type, node.Member));
|
|
return base.VisitMember(node);
|
|
}
|
|
|
|
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override MemberBinding VisitMemberBinding(MemberBinding node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitMemberInit(MemberInitExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override MemberListBinding VisitMemberListBinding(MemberListBinding node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitMethodCall(MethodCallExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new MethodCallExpressionFingerprint(node.NodeType, node.Type, node.Method));
|
|
return base.VisitMethodCall(node);
|
|
}
|
|
|
|
protected override Expression VisitNew(NewExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitNewArray(NewArrayExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitParameter(ParameterExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
|
|
int parameterIndex = _seenParameters.IndexOf(node);
|
|
if (parameterIndex < 0) {
|
|
// first time seeing this parameter
|
|
parameterIndex = _seenParameters.Count;
|
|
_seenParameters.Add(node);
|
|
}
|
|
|
|
_currentChain.Elements.Add(new ParameterExpressionFingerprint(node.NodeType, node.Type, parameterIndex));
|
|
return base.VisitParameter(node);
|
|
}
|
|
|
|
protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitSwitch(SwitchExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override SwitchCase VisitSwitchCase(SwitchCase node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitTry(TryExpression node) {
|
|
return GiveUp(node);
|
|
}
|
|
|
|
protected override Expression VisitTypeBinary(TypeBinaryExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new TypeBinaryExpressionFingerprint(node.NodeType, node.Type, node.TypeOperand));
|
|
return base.VisitTypeBinary(node);
|
|
}
|
|
|
|
protected override Expression VisitUnary(UnaryExpression node) {
|
|
if (_gaveUp) { return node; }
|
|
_currentChain.Elements.Add(new UnaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
|
|
return base.VisitUnary(node);
|
|
}
|
|
|
|
}
|
|
}
|