diff options
Diffstat (limited to 'src/Microsoft.Web.Mvc/ExpressionUtil/FingerprintingExpressionVisitor.cs')
-rw-r--r-- | src/Microsoft.Web.Mvc/ExpressionUtil/FingerprintingExpressionVisitor.cs | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/src/Microsoft.Web.Mvc/ExpressionUtil/FingerprintingExpressionVisitor.cs b/src/Microsoft.Web.Mvc/ExpressionUtil/FingerprintingExpressionVisitor.cs new file mode 100644 index 00000000..3bed0dd7 --- /dev/null +++ b/src/Microsoft.Web.Mvc/ExpressionUtil/FingerprintingExpressionVisitor.cs @@ -0,0 +1,296 @@ +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace Microsoft.Web.Mvc.ExpressionUtil +{ + // 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(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); + } + } +} |