< Summary

Class:Azure.Data.Tables.Queryable.ExpressionNormalizer
Assembly:Azure.Data.Tables
File(s):C:\Git\azure-sdk-for-net\sdk\tables\Azure.Data.Tables\src\Queryable\ExpressionNormalizer.cs
Covered lines:73
Uncovered lines:14
Coverable lines:87
Total lines:263
Line coverage:83.9% (73 of 87)
Covered branches:64
Total branches:90
Branch coverage:71.1% (64 of 90)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-100%100%
get_NormalizerRewrites()-100%100%
Normalize(...)-100%100%
VisitBinary(...)-100%100%
VisitUnary(...)-100%100%
UnwrapObjectConvert(...)-50%70%
IsConstantZero(...)-100%50%
VisitMethodCall(...)-100%100%
VisitMethodCallNoRewrite(...)-64.29%62.5%
.cctor()-100%100%
RelationalOperatorPlaceholder(...)-0%100%
CreateRelationalOperator(...)-100%100%
TryCreateRelationalOperator(...)-73.33%41.67%
CreateCompareExpression(...)-100%100%
RecordRewrite(...)-100%100%
.ctor(...)-100%100%
get_Kind()-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\tables\Azure.Data.Tables\src\Queryable\ExpressionNormalizer.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Linq.Expressions;
 8using System.Reflection;
 9
 10namespace Azure.Data.Tables.Queryable
 11{
 12    internal class ExpressionNormalizer : LinqExpressionVisitor
 13    {
 14        private const bool LiftToNull = false;
 15
 46016        private readonly Dictionary<Expression, Pattern> _patterns = new Dictionary<Expression, Pattern>(ReferenceEquali
 17
 46018        private ExpressionNormalizer(Dictionary<Expression, Expression> normalizerRewrites)
 19        {
 20            Debug.Assert(normalizerRewrites != null, "normalizerRewrites != null");
 46021            NormalizerRewrites = normalizerRewrites;
 46022        }
 23
 29424        internal Dictionary<Expression, Expression> NormalizerRewrites { get; }
 25
 26        internal static Expression Normalize(Expression expression, Dictionary<Expression, Expression> rewrites)
 27        {
 28            Debug.Assert(expression != null, "expression != null");
 29            Debug.Assert(rewrites != null, "rewrites != null");
 30
 46031            ExpressionNormalizer normalizer = new ExpressionNormalizer(rewrites);
 46032            Expression result = normalizer.Visit(expression);
 46033            return result;
 34        }
 35
 36        internal override Expression VisitBinary(BinaryExpression b)
 37        {
 114838            BinaryExpression visited = (BinaryExpression)base.VisitBinary(b);
 39
 114840            switch (visited.NodeType)
 41            {
 42                case ExpressionType.Equal:
 43                case ExpressionType.NotEqual:
 44                case ExpressionType.LessThan:
 45                case ExpressionType.LessThanOrEqual:
 46                case ExpressionType.GreaterThan:
 47                case ExpressionType.GreaterThanOrEqual:
 48
 80049                    Expression normalizedLeft = UnwrapObjectConvert(visited.Left);
 80050                    Expression normalizedRight = UnwrapObjectConvert(visited.Right);
 80051                    if (normalizedLeft != visited.Left || normalizedRight != visited.Right)
 52                    {
 2653                        visited = CreateRelationalOperator(visited.NodeType, normalizedLeft, normalizedRight);
 54                    }
 55                    break;
 56            }
 57
 114858            if (_patterns.TryGetValue(visited.Left, out Pattern pattern) && pattern.Kind == PatternKind.Compare && IsCon
 59            {
 6460                ComparePattern comparePattern = (ComparePattern)pattern;
 6461                if (TryCreateRelationalOperator(visited.NodeType, comparePattern.Left, comparePattern.Right, out BinaryE
 62                {
 6463                    visited = relationalExpression;
 64                }
 65            }
 66
 114867            RecordRewrite(b, visited);
 68
 114869            return visited;
 70        }
 71
 72        internal override Expression VisitUnary(UnaryExpression u)
 73        {
 5074            UnaryExpression visited = (UnaryExpression)base.VisitUnary(u);
 5075            Expression result = visited;
 76
 5077            RecordRewrite(u, result);
 78
 5079            return result;
 80        }
 81
 82        private static Expression UnwrapObjectConvert(Expression input)
 83        {
 160084            if (input.NodeType == ExpressionType.Constant && input.Type == typeof(object))
 85            {
 086                ConstantExpression constant = (ConstantExpression)input;
 87
 088                if (constant.Value != null &&
 089                    constant.Value.GetType() != typeof(object))
 90                {
 091                    return Expression.Constant(constant.Value, constant.Value.GetType());
 92                }
 93            }
 94
 162695            while (ExpressionType.Convert == input.NodeType)
 96            {
 2697                input = ((UnaryExpression)input).Operand;
 98            }
 99
 1600100            return input;
 101        }
 102
 103        private static bool IsConstantZero(Expression expression)
 104        {
 64105            return expression.NodeType == ExpressionType.Constant &&
 64106                ((ConstantExpression)expression).Value.Equals(0);
 107        }
 108
 109        internal override Expression VisitMethodCall(MethodCallExpression call)
 110        {
 276111            Expression visited = VisitMethodCallNoRewrite(call);
 276112            RecordRewrite(call, visited);
 276113            return visited;
 114        }
 115
 116        internal Expression VisitMethodCallNoRewrite(MethodCallExpression call)
 117        {
 276118            MethodCallExpression visited = (MethodCallExpression)base.VisitMethodCall(call);
 119
 276120            if (visited.Method.IsStatic && visited.Method.Name == "Equals" && visited.Arguments.Count > 1)
 121            {
 0122                return Expression.Equal(visited.Arguments[0], visited.Arguments[1], false, visited.Method);
 123            }
 124
 276125            if (!visited.Method.IsStatic && visited.Method.Name == "Equals" && visited.Arguments.Count > 0)
 126            {
 0127                return CreateRelationalOperator(ExpressionType.Equal, visited.Object, visited.Arguments[0]);
 128            }
 129
 276130            if (visited.Method.IsStatic && visited.Method.Name == "CompareString" && visited.Method.DeclaringType.FullNa
 131            {
 0132                return CreateCompareExpression(visited.Arguments[0], visited.Arguments[1]);
 133            }
 134
 276135            if (!visited.Method.IsStatic && visited.Method.Name == "CompareTo" && visited.Arguments.Count == 1 && visite
 136            {
 64137                return CreateCompareExpression(visited.Object, visited.Arguments[0]);
 138            }
 139
 212140            if (visited.Method.IsStatic && visited.Method.Name == "Compare" && visited.Arguments.Count > 1 && visited.Me
 141            {
 0142                return CreateCompareExpression(visited.Arguments[0], visited.Arguments[1]);
 143            }
 144
 212145            if (ReflectionUtil.s_dictionaryMethodInfosHash.Contains(visited.Method) && visited.Arguments.Count == 1 && v
 146            {
 212147                return visited;
 148            }
 149
 0150            throw new NotSupportedException($"Method {visited.Method.Name} not supported.");
 151        }
 152
 2153        private static readonly MethodInfo StaticRelationalOperatorPlaceholderMethod = typeof(ExpressionNormalizer).GetM
 154
 155        private static bool RelationalOperatorPlaceholder<TLeft, TRight>(TLeft left, TRight right)
 156        {
 157            Debug.Assert(false, "This method should never be called. It exists merely to support creation of relational 
 0158            return object.ReferenceEquals(left, right);
 159        }
 160
 161        private static BinaryExpression CreateRelationalOperator(ExpressionType op, Expression left, Expression right)
 162        {
 154163            if (!TryCreateRelationalOperator(op, left, right, out BinaryExpression result))
 164            {
 165                Debug.Assert(false, "CreateRelationalOperator has unknown op " + op);
 166            }
 167
 154168            return result;
 169        }
 170
 171        private static bool TryCreateRelationalOperator(ExpressionType op, Expression left, Expression right, out Binary
 172        {
 218173            MethodInfo relationalOperatorPlaceholderMethod = StaticRelationalOperatorPlaceholderMethod.MakeGenericMethod
 174
 175            switch (op)
 176            {
 177                case ExpressionType.Equal:
 64178                    result = Expression.Equal(left, right, LiftToNull, relationalOperatorPlaceholderMethod);
 64179                    return true;
 180
 181                case ExpressionType.NotEqual:
 0182                    result = Expression.NotEqual(left, right, LiftToNull, relationalOperatorPlaceholderMethod);
 0183                    return true;
 184
 185                case ExpressionType.LessThan:
 12186                    result = Expression.LessThan(left, right, LiftToNull, relationalOperatorPlaceholderMethod);
 12187                    return true;
 188
 189                case ExpressionType.LessThanOrEqual:
 4190                    result = Expression.LessThanOrEqual(left, right, LiftToNull, relationalOperatorPlaceholderMethod);
 4191                    return true;
 192
 193                case ExpressionType.GreaterThan:
 68194                    result = Expression.GreaterThan(left, right, LiftToNull, relationalOperatorPlaceholderMethod);
 68195                    return true;
 196
 197                case ExpressionType.GreaterThanOrEqual:
 70198                    result = Expression.GreaterThanOrEqual(left, right, LiftToNull, relationalOperatorPlaceholderMethod)
 70199                    return true;
 200
 201                default:
 0202                    result = null;
 0203                    return false;
 204            }
 205        }
 206
 207        private Expression CreateCompareExpression(Expression left, Expression right)
 208        {
 64209            Expression result = Expression.Condition(
 64210                CreateRelationalOperator(ExpressionType.Equal, left, right),
 64211                Expression.Constant(0),
 64212                Expression.Condition(
 64213                    CreateRelationalOperator(ExpressionType.GreaterThan, left, right),
 64214                    Expression.Constant(1),
 64215                    Expression.Constant(-1)));
 216
 64217            _patterns[result] = new ComparePattern(left, right);
 218
 64219            return result;
 220        }
 221
 222        private void RecordRewrite(Expression source, Expression rewritten)
 223        {
 224            Debug.Assert(source != null, "source != null");
 225            Debug.Assert(rewritten != null, "rewritten != null");
 226            Debug.Assert(NormalizerRewrites != null, "this.NormalizerRewrites != null");
 227
 1474228            if (source != rewritten)
 229            {
 294230                NormalizerRewrites.Add(rewritten, source);
 231            }
 1474232        }
 233
 234        private abstract class Pattern
 235        {
 236            internal abstract PatternKind Kind { get; }
 237        }
 238
 239        private enum PatternKind
 240        {
 241            Compare,
 242        }
 243
 244        private sealed class ComparePattern : Pattern
 245        {
 64246            internal ComparePattern(Expression left, Expression right)
 247            {
 64248                Left = left;
 64249                Right = right;
 64250            }
 251
 252            internal readonly Expression Left;
 253
 254            internal readonly Expression Right;
 255
 256            internal override PatternKind Kind
 257            {
 64258                get { return PatternKind.Compare; }
 259            }
 260        }
 261
 262    }
 263}