static void Path(PathInfo info, Expression expr, Expression path)
        {
#if DEBUG
            _callCounter1++;
#endif

            if (expr == null)
            {
                return;
            }

            switch (expr.NodeType)
            {
            case ExpressionType.Add:
            case ExpressionType.AddChecked:
            case ExpressionType.And:
            case ExpressionType.AndAlso:
            case ExpressionType.ArrayIndex:
            case ExpressionType.Assign:
            case ExpressionType.Coalesce:
            case ExpressionType.Divide:
            case ExpressionType.Equal:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LeftShift:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.Modulo:
            case ExpressionType.Multiply:
            case ExpressionType.MultiplyChecked:
            case ExpressionType.NotEqual:
            case ExpressionType.Or:
            case ExpressionType.OrElse:
            case ExpressionType.Power:
            case ExpressionType.RightShift:
            case ExpressionType.Subtract:
            case ExpressionType.SubtractChecked:
            {
                path = ConvertTo(path, typeof(BinaryExpression));

                Path(info, ((BinaryExpression)expr).Conversion, Expression.Property(path, ReflectionHelper.Binary.Conversion));
                Path(info, ((BinaryExpression)expr).Left, Expression.Property(path, ReflectionHelper.Binary.Left));
                Path(info, ((BinaryExpression)expr).Right, Expression.Property(path, ReflectionHelper.Binary.Right));

                break;
            }

            case ExpressionType.ArrayLength:
            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
            case ExpressionType.Not:
            case ExpressionType.Quote:
            case ExpressionType.TypeAs:
            case ExpressionType.UnaryPlus:
                Path(
                    info,
                    ((UnaryExpression)expr).Operand,
                    path = ConvertTo(path, typeof(UnaryExpression)),
                    ReflectionHelper.Unary.Operand);
                break;

            case ExpressionType.Call:
            {
                path = ConvertTo(path, typeof(MethodCallExpression));

                Path(info, ((MethodCallExpression)expr).Object, path, ReflectionHelper.MethodCall.Object);
                Path(info, ((MethodCallExpression)expr).Arguments, path, ReflectionHelper.MethodCall.Arguments);

                break;
            }

            case ExpressionType.Conditional:
            {
                path = ConvertTo(path, typeof(ConditionalExpression));

                Path(info, ((ConditionalExpression)expr).Test, path, ReflectionHelper.Conditional.Test);
                Path(info, ((ConditionalExpression)expr).IfTrue, path, ReflectionHelper.Conditional.IfTrue);
                Path(info, ((ConditionalExpression)expr).IfFalse, path, ReflectionHelper.Conditional.IfFalse);

                break;
            }

            case ExpressionType.Invoke:
            {
                path = ConvertTo(path, typeof(InvocationExpression));

                Path(info, ((InvocationExpression)expr).Expression, path, ReflectionHelper.Invocation.Expression);
                Path(info, ((InvocationExpression)expr).Arguments, path, ReflectionHelper.Invocation.Arguments);

                break;
            }

            case ExpressionType.Lambda:
            {
                path = ConvertTo(path, typeof(LambdaExpression));

                Path(info, ((LambdaExpression)expr).Body, path, ReflectionHelper.LambdaExpr.Body);
                Path(info, ((LambdaExpression)expr).Parameters, path, ReflectionHelper.LambdaExpr.Parameters);

                break;
            }

            case ExpressionType.ListInit:
            {
                path = ConvertTo(path, typeof(ListInitExpression));

                Path(info, ((ListInitExpression)expr).NewExpression, path, ReflectionHelper.ListInit.NewExpression);
                Path(((ListInitExpression)expr).Initializers, path, ReflectionHelper.ListInit.Initializers,
                     (ex, p) => Path(info, ex.Arguments, p, ReflectionHelper.ElementInit.Arguments));

                break;
            }

            case ExpressionType.MemberAccess:
                Path(
                    info,
                    ((MemberExpression)expr).Expression,
                    path = ConvertTo(path, typeof(MemberExpression)),
                    ReflectionHelper.Member.Expression);
                break;

            case ExpressionType.MemberInit:
            {
                void Modify(MemberBinding b, Expression pinf)
                {
                    switch (b.BindingType)
                    {
                    case MemberBindingType.Assignment:
                        Path(
                            info,
                            ((MemberAssignment)b).Expression,
                            ConvertTo(pinf, typeof(MemberAssignment)),
                            ReflectionHelper.MemberAssignmentBind.Expression);
                        break;

                    case MemberBindingType.ListBinding:
                        Path(
                            ((MemberListBinding)b).Initializers,
                            ConvertTo(pinf, typeof(MemberListBinding)),
                            ReflectionHelper.MemberListBind.Initializers,
                            (p, psi) => Path(info, p.Arguments, psi, ReflectionHelper.ElementInit.Arguments));
                        break;

                    case MemberBindingType.MemberBinding:
                        Path(
                            ((MemberMemberBinding)b).Bindings,
                            ConvertTo(pinf, typeof(MemberMemberBinding)),
                            ReflectionHelper.MemberMemberBind.Bindings,
                            Modify);
                        break;
                    }
                }

                path = ConvertTo(path, typeof(MemberInitExpression));

                Path(info, ((MemberInitExpression)expr).NewExpression, path, ReflectionHelper.MemberInit.NewExpression);
                Path(((MemberInitExpression)expr).Bindings, path, ReflectionHelper.MemberInit.Bindings, Modify);

                break;
            }

            case ExpressionType.New:
                Path(
                    info,
                    ((NewExpression)expr).Arguments,
                    path = ConvertTo(path, typeof(NewExpression)),
                    ReflectionHelper.New.Arguments);
                break;

            case ExpressionType.NewArrayBounds:
                Path(
                    info,
                    ((NewArrayExpression)expr).Expressions,
                    path = ConvertTo(path, typeof(NewArrayExpression)),
                    ReflectionHelper.NewArray.Expressions);
                break;

            case ExpressionType.NewArrayInit:
                Path(
                    info,
                    ((NewArrayExpression)expr).Expressions,
                    path = ConvertTo(path, typeof(NewArrayExpression)),
                    ReflectionHelper.NewArray.Expressions);
                break;

            case ExpressionType.TypeIs:
                Path(
                    info,
                    ((TypeBinaryExpression)expr).Expression,
                    path = ConvertTo(path, typeof(TypeBinaryExpression)),
                    ReflectionHelper.TypeBinary.Expression);
                break;

            case ExpressionType.Block:
            {
                path = ConvertTo(path, typeof(BlockExpression));

                Path(info, ((BlockExpression)expr).Expressions, path, ReflectionHelper.Block.Expressions);
                Path(info, ((BlockExpression)expr).Variables, path, ReflectionHelper.Block.Variables);                                  // ?

                break;
            }

            case ExpressionType.Constant:
            {
                path = ConvertTo(path, typeof(ConstantExpression));

                if (((ConstantExpression)expr).Value is IQueryable iq && !info.Visited.Contains(iq.Expression))
                {
                    info.Visited.Add(iq.Expression);

                    Expression p = Expression.Property(path, ReflectionHelper.Constant.Value);
                    p = ConvertTo(p, typeof(IQueryable));
                    Path(info, iq.Expression, p, ReflectionHelper.QueryableInt.Expression);
                }

                break;
            }

            case ExpressionType.Parameter: path = ConvertTo(path, typeof(ParameterExpression)); break;

            case ExpressionType.Extension:
            {
                if (expr.CanReduce)
                {
                    expr = expr.Reduce();
                    Path(info, expr, path);
                }
                break;
            }
            }

            info.Func(expr, path);
        }