Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / ExpressionHelper.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Collections.Generic;\r
16     using System.Globalization;\r
17     using System.Linq;\r
18     using System.Linq.Expressions;\r
19     using System.Reflection;\r
20     using System.Web.Mvc.Resources;\r
21 \r
22     public static class ExpressionHelper {\r
23         public static string GetExpressionText(string expression) {\r
24             return\r
25                 String.Equals(expression, "model", StringComparison.OrdinalIgnoreCase)\r
26                     ? String.Empty    // If it's exactly "model", then give them an empty string, to replicate the lambda behavior\r
27                     : expression;\r
28         }\r
29 \r
30         public static string GetExpressionText(LambdaExpression expression) {\r
31             // Crack the expression string for property/field accessors to create its name\r
32             Stack<string> nameParts = new Stack<string>();\r
33             Expression part = expression.Body;\r
34 \r
35             while (part != null) {\r
36                 if (part.NodeType == ExpressionType.Call) {\r
37                     MethodCallExpression methodExpression = (MethodCallExpression)part;\r
38 \r
39                     if (!IsSingleArgumentIndexer(methodExpression)) {\r
40                         break;\r
41                     }\r
42 \r
43                     nameParts.Push(\r
44                         GetIndexerInvocation(\r
45                             methodExpression.Arguments.Single(),\r
46                             expression.Parameters.ToArray()\r
47                         )\r
48                     );\r
49 \r
50                     part = methodExpression.Object;\r
51                 }\r
52                 else if (part.NodeType == ExpressionType.ArrayIndex) {\r
53                     BinaryExpression binaryExpression = (BinaryExpression)part;\r
54 \r
55                     nameParts.Push(\r
56                         GetIndexerInvocation(\r
57                             binaryExpression.Right,\r
58                             expression.Parameters.ToArray()\r
59                         )\r
60                     );\r
61 \r
62                     part = binaryExpression.Left;\r
63                 }\r
64                 else if (part.NodeType == ExpressionType.MemberAccess) {\r
65                     MemberExpression memberExpressionPart = (MemberExpression)part;\r
66                     nameParts.Push("." + memberExpressionPart.Member.Name);\r
67                     part = memberExpressionPart.Expression;\r
68                 }\r
69                 else {\r
70                     break;\r
71                 }\r
72             }\r
73 \r
74             // If it starts with "model", then strip that away\r
75             if (nameParts.Count > 0 && String.Equals(nameParts.Peek(), ".model", StringComparison.OrdinalIgnoreCase)) {\r
76                 nameParts.Pop();\r
77             }\r
78 \r
79             if (nameParts.Count > 0) {\r
80                 return nameParts.Aggregate((left, right) => left + right).TrimStart('.');\r
81             }\r
82 \r
83             return String.Empty;\r
84         }\r
85 \r
86         private static string GetIndexerInvocation(Expression expression, ParameterExpression[] parameters) {\r
87             Expression converted = Expression.Convert(expression, typeof(object));\r
88             ParameterExpression fakeParameter = Expression.Parameter(typeof(object), null);\r
89             Expression<Func<object, object>> lambda = Expression.Lambda<Func<object, object>>(converted, fakeParameter);\r
90             Func<object, object> func;\r
91 \r
92             try {\r
93                 func = ExpressionUtil.CachedExpressionCompiler.Process(lambda);\r
94             }\r
95             catch (InvalidOperationException ex) {\r
96                 throw new InvalidOperationException(\r
97                     String.Format(\r
98                         CultureInfo.CurrentUICulture,\r
99                         MvcResources.ExpressionHelper_InvalidIndexerExpression,\r
100                         expression,\r
101                         parameters[0].Name\r
102                     ),\r
103                     ex\r
104                 );\r
105             }\r
106 \r
107             return "[" + Convert.ToString(func(null), CultureInfo.InvariantCulture) + "]";\r
108         }\r
109 \r
110         internal static bool IsSingleArgumentIndexer(Expression expression) {\r
111             MethodCallExpression methodExpression = expression as MethodCallExpression;\r
112             if (methodExpression == null || methodExpression.Arguments.Count != 1) {\r
113                 return false;\r
114             }\r
115 \r
116             return methodExpression.Method\r
117                                    .DeclaringType\r
118                                    .GetDefaultMembers()\r
119                                    .OfType<PropertyInfo>()\r
120                                    .Any(p => p.GetGetMethod() == methodExpression.Method);\r
121         }\r
122     }\r
123 }\r