< Summary

Class:Azure.Data.Tables.Queryable.ExpressionWriter
Assembly:Azure.Data.Tables
File(s):C:\Git\azure-sdk-for-net\sdk\tables\Azure.Data.Tables\src\Queryable\ExpressionWriter.cs
Covered lines:63
Uncovered lines:21
Coverable lines:84
Total lines:249
Line coverage:75% (63 of 84)
Covered branches:36
Total branches:91
Branch coverage:39.5% (36 of 91)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor()-100%100%
ExpressionToString(...)-100%100%
ConvertExpressionToString(...)-75%50%
Visit(...)-100%100%
VisitMethodCall(...)-75%50%
VisitMemberAccess(...)-70%50%
VisitConstant(...)-57.14%50%
VisitUnary(...)-54.55%40%
VisitBinary(...)-88.89%50%
VisitParameter(...)-100%100%
IsInputReference(...)-100%100%
VisitOperand(...)-100%100%
Translate(...)-100%100%
TranslateMemberName(...)-100%100%
TranslateOperator(...)-53.33%22.22%

File(s)

C:\Git\azure-sdk-for-net\sdk\tables\Azure.Data.Tables\src\Queryable\ExpressionWriter.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.Globalization;
 8using System.Linq.Expressions;
 9using System.Reflection;
 10using System.Text;
 11
 12namespace Azure.Data.Tables.Queryable
 13{
 14    internal class ExpressionWriter : LinqExpressionVisitor
 15    {
 16        internal readonly StringBuilder _builder;
 17        private readonly Stack<Expression> _expressionStack;
 18        private bool _cantTranslateExpression;
 19
 46020        protected ExpressionWriter()
 21        {
 46022            _builder = new StringBuilder();
 46023            _expressionStack = new Stack<Expression>();
 46024            _expressionStack.Push(null);
 46025        }
 26
 27        internal static string ExpressionToString(Expression e)
 28        {
 46029            ExpressionWriter ew = new ExpressionWriter();
 46030            return ew.ConvertExpressionToString(e);
 31        }
 32
 33        internal string ConvertExpressionToString(Expression e)
 34        {
 46035            string serialized = Translate(e);
 36
 46037            if (_cantTranslateExpression)
 38            {
 039                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.ALinqCantTranslateExpressio
 40            }
 41
 46042            return serialized;
 43        }
 44
 45        internal override Expression Visit(Expression exp)
 46        {
 336047            _expressionStack.Push(exp);
 336048            Expression result = base.Visit(exp);
 336049            _expressionStack.Pop();
 336050            return result;
 51        }
 52
 53        internal override Expression VisitMethodCall(MethodCallExpression m)
 54        {
 21255            if (ReflectionUtil.s_dictionaryMethodInfosHash.Contains(m.Method) && m.Arguments.Count == 1 && m.Arguments[0
 56            {
 21257                _builder.Append(ce.Value as string);
 58            }
 59            else
 60            {
 061                return base.VisitMethodCall(m);
 62            }
 63
 21264            return m;
 65        }
 66
 67        internal override Expression VisitMemberAccess(MemberExpression m)
 68        {
 58869            if (m.Member is FieldInfo)
 70            {
 071                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.ALinqCantReferToPublicField
 72            }
 73
 58874            Expression e = Visit(m.Expression);
 58875            if (m.Member.Name == "Value" && m.Member.DeclaringType.IsGenericType
 58876                && m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>))
 77            {
 078                return m;
 79            }
 80
 58881            if (!IsInputReference(e) && e.NodeType != ExpressionType.Convert && e.NodeType != ExpressionType.ConvertChec
 82            {
 083                _builder.Append(UriHelper.FORWARDSLASH);
 84            }
 85
 58886            _builder.Append(TranslateMemberName(m.Member.Name));
 87
 58888            return m;
 89        }
 90
 91        internal override Expression VisitConstant(ConstantExpression c)
 92        {
 93            string result;
 80894            if (c.Value == null)
 95            {
 096                _builder.Append(UriHelper.NULL);
 097                return c;
 98            }
 80899            else if (!ClientConvert.TryKeyPrimitiveToString(c.Value, out result))
 100            {
 0101                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.ALinqCouldNotConvert, c
 102            }
 103
 104            Debug.Assert(result != null, "result != null");
 105
 106            // A Difference from WCF Data Services is that we will escape later when we execute the fully parsed query.
 808107            _builder.Append(result);
 808108            return c;
 109        }
 110
 111        internal override Expression VisitUnary(UnaryExpression u)
 112        {
 16113            switch (u.NodeType)
 114            {
 115                case ExpressionType.Not:
 16116                    _builder.Append(UriHelper.NOT);
 16117                    _builder.Append(UriHelper.SPACE);
 16118                    VisitOperand(u.Operand);
 16119                    break;
 120                case ExpressionType.Negate:
 121                case ExpressionType.NegateChecked:
 0122                    _builder.Append(UriHelper.SPACE);
 0123                    _builder.Append(TranslateOperator(u.NodeType));
 0124                    VisitOperand(u.Operand);
 0125                    break;
 126                case ExpressionType.Convert:
 127                case ExpressionType.ConvertChecked:
 128                case ExpressionType.UnaryPlus:
 129                    break;
 130                default:
 0131                    _cantTranslateExpression = true;
 132                    break;
 133            }
 134
 16135            return u;
 136        }
 137
 138        internal override Expression VisitBinary(BinaryExpression b)
 139        {
 1148140            VisitOperand(b.Left);
 1148141            _builder.Append(UriHelper.SPACE);
 1148142            string operatorString = TranslateOperator(b.NodeType);
 1148143            if (string.IsNullOrEmpty(operatorString))
 144            {
 0145                _cantTranslateExpression = true;
 146            }
 147            else
 148            {
 1148149                _builder.Append(operatorString);
 150            }
 151
 1148152            _builder.Append(UriHelper.SPACE);
 1148153            VisitOperand(b.Right);
 1148154            return b;
 155        }
 156
 157        internal override Expression VisitParameter(ParameterExpression p)
 158        {
 588159            return p;
 160        }
 161
 162        private static bool IsInputReference(Expression exp)
 163        {
 588164            return exp is ParameterExpression;
 165        }
 166
 167        private void VisitOperand(Expression e)
 168        {
 2312169            if (e is BinaryExpression || e is UnaryExpression)
 170            {
 720171                if (e is UnaryExpression unary && unary.NodeType == ExpressionType.TypeAs)
 172                {
 8173                    Visit(unary.Operand);
 174                }
 175                else
 176                {
 712177                    _builder.Append(UriHelper.LEFTPAREN);
 712178                    Visit(e);
 712179                    _builder.Append(UriHelper.RIGHTPAREN);
 180                }
 181
 182            }
 183            else
 184            {
 1592185                Visit(e);
 186            }
 1592187        }
 188
 189        private string Translate(Expression e)
 190        {
 460191            Visit(e);
 460192            return _builder.ToString();
 193        }
 194
 195        protected virtual string TranslateMemberName(string memberName)
 196        {
 588197            return memberName;
 198        }
 199
 200        protected virtual string TranslateOperator(ExpressionType type)
 201        {
 202            switch (type)
 203            {
 204                case ExpressionType.AndAlso:
 205                case ExpressionType.And:
 272206                    return UriHelper.AND;
 207                case ExpressionType.OrElse:
 208                case ExpressionType.Or:
 76209                    return UriHelper.OR;
 210                case ExpressionType.Equal:
 428211                    return UriHelper.EQ;
 212                case ExpressionType.NotEqual:
 20213                    return UriHelper.NE;
 214                case ExpressionType.LessThan:
 32215                    return UriHelper.LT;
 216                case ExpressionType.LessThanOrEqual:
 4217                    return UriHelper.LE;
 218                case ExpressionType.GreaterThan:
 12219                    return UriHelper.GT;
 220                case ExpressionType.GreaterThanOrEqual:
 304221                    return UriHelper.GE;
 222                case ExpressionType.Add:
 223                case ExpressionType.AddChecked:
 0224                    return UriHelper.ADD;
 225                case ExpressionType.Subtract:
 226                case ExpressionType.SubtractChecked:
 0227                    return UriHelper.SUB;
 228                case ExpressionType.Multiply:
 229                case ExpressionType.MultiplyChecked:
 0230                    return UriHelper.MUL;
 231                case ExpressionType.Divide:
 0232                    return UriHelper.DIV;
 233                case ExpressionType.Modulo:
 0234                    return UriHelper.MOD;
 235                case ExpressionType.Negate:
 236                case ExpressionType.NegateChecked:
 0237                    return UriHelper.NEGATE;
 238                case ExpressionType.ArrayIndex:
 239                case ExpressionType.Power:
 240                case ExpressionType.Coalesce:
 241                case ExpressionType.ExclusiveOr:
 242                case ExpressionType.LeftShift:
 243                case ExpressionType.RightShift:
 244                default:
 0245                    return null;
 246            }
 247        }
 248    }
 249}