Remove excessive shortcut key matching in ToolStrip
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / ContractNameServices.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.Globalization;\r
7 using System.Reflection;\r
8 using System.Text;\r
9 using Microsoft.Internal;\r
10 \r
11 namespace System.ComponentModel.Composition\r
12 {\r
13     internal static class ContractNameServices\r
14     {\r
15         const char NamespaceSeparator = '.';\r
16         const char ArrayOpeningBracket = '[';\r
17         const char ArrayClosingBracket = ']';\r
18         const char ArraySeparator = ',';\r
19         const char PointerSymbol = '*';\r
20         const char ReferenceSymbol = '&';\r
21         const char GenericArityBackQuote = '`';\r
22         const char NestedClassSeparator = '+';\r
23         const char ContractNameGenericOpeningBracket = '(';\r
24         const char ContractNameGenericClosingBracket = ')';\r
25         const char ContractNameGenericArgumentSeparator = ',';\r
26         const char CustomModifiersSeparator = ' ';\r
27 \r
28         [ThreadStatic]\r
29         private static Dictionary<Type, string> typeIdentityCache;\r
30 \r
31         private static Dictionary<Type, string> TypeIdentityCache\r
32         {\r
33             get\r
34             {\r
35                 return typeIdentityCache = typeIdentityCache ?? new Dictionary<Type, string>();\r
36             }\r
37         }\r
38 \r
39         internal static string GetTypeIdentity(Type type)\r
40         {\r
41             Assumes.NotNull(type);\r
42             string typeIdentity = null;\r
43 \r
44             if (!TypeIdentityCache.TryGetValue(type, out typeIdentity))\r
45             {\r
46                 if (!type.IsAbstract && type.IsSubclassOf(typeof(Delegate)))\r
47                 {\r
48                     MethodInfo method = type.GetMethod("Invoke");\r
49                     typeIdentity = ContractNameServices.GetTypeIdentityFromMethod(method);\r
50                 }\r
51                 else\r
52                 {\r
53                     StringBuilder typeIdentityStringBuilder = new StringBuilder();\r
54                     WriteTypeWithNamespace(typeIdentityStringBuilder, type);\r
55                     typeIdentity = typeIdentityStringBuilder.ToString();\r
56                 }\r
57 \r
58                 TypeIdentityCache.Add(type, typeIdentity);\r
59             }\r
60 \r
61             return typeIdentity;\r
62         }\r
63 \r
64         internal static string GetTypeIdentityFromMethod(MethodInfo method)\r
65         {\r
66             StringBuilder methodNameStringBuilder = new StringBuilder();\r
67 \r
68             WriteTypeWithNamespace(methodNameStringBuilder, method.ReturnType);\r
69 \r
70             methodNameStringBuilder.Append("(");\r
71 \r
72             ParameterInfo[] parameters = method.GetParameters();\r
73 \r
74             for (int i = 0; i < parameters.Length; i++)\r
75             {\r
76                 if (i != 0)\r
77                 {\r
78                     methodNameStringBuilder.Append(",");\r
79                 }\r
80 \r
81                 WriteTypeWithNamespace(methodNameStringBuilder, parameters[i].ParameterType);\r
82             }\r
83             methodNameStringBuilder.Append(")");\r
84 \r
85             return methodNameStringBuilder.ToString();\r
86         }\r
87        \r
88         private static void WriteTypeWithNamespace(StringBuilder typeName, Type type)\r
89         {\r
90             // Writes type with namesapce\r
91             if (!string.IsNullOrEmpty(type.Namespace))\r
92             {\r
93                 typeName.Append(type.Namespace);\r
94                 typeName.Append(NamespaceSeparator);\r
95             }\r
96             WriteType(typeName, type);\r
97         }\r
98 \r
99         private static void WriteType(StringBuilder typeName, Type type)\r
100         {\r
101             // Writes type name\r
102             if (type.IsGenericType)\r
103             {\r
104                 //\r
105                 // Reflection format stores all the generic arguments (including the ones for parent types) on the leaf type.\r
106                 // These arguments are placed in a queue and are written out based on generic arity (`X) of each type\r
107                 //\r
108                 Queue<Type> genericTypeArguments = new Queue<Type>(type.GetGenericArguments());\r
109                 WriteGenericType(typeName, type, type.IsGenericTypeDefinition, genericTypeArguments);\r
110                 Assumes.IsTrue(genericTypeArguments.Count == 0, "Expecting genericTypeArguments queue to be empty.");\r
111             }\r
112             else\r
113             {\r
114                 WriteNonGenericType(typeName, type);\r
115             }\r
116         }\r
117 \r
118         private static void WriteNonGenericType(StringBuilder typeName, Type type)\r
119         {\r
120             //\r
121             // Writes non-generic type\r
122             //\r
123             if (type.DeclaringType != null)\r
124             {\r
125                 WriteType(typeName, type.DeclaringType);\r
126                 typeName.Append(NestedClassSeparator);\r
127             }\r
128             if (type.IsArray)\r
129             {\r
130                 WriteArrayType(typeName, type);\r
131             }\r
132             else if (type.IsPointer)\r
133             {\r
134                 WritePointerType(typeName, type);\r
135             }\r
136             else if (type.IsByRef)\r
137             {\r
138                 WriteByRefType(typeName, type);\r
139             }\r
140             else\r
141             {\r
142                 typeName.Append(type.Name);\r
143             }\r
144         }\r
145 \r
146         private static void WriteArrayType(StringBuilder typeName, Type type)\r
147         {\r
148             //\r
149             // Writes array type  e.g <TypeName>[]\r
150             // Note that jagged arrays are stored in reverse order\r
151             // e.g. C#: Int32[][,]  Reflection: Int32[,][]\r
152             // we are following C# order for arrays\r
153             //\r
154             Type rootElementType = FindArrayElementType(type);\r
155             WriteType(typeName, rootElementType);\r
156             Type elementType = type;\r
157             do\r
158             {\r
159                 WriteArrayTypeDimensions(typeName, elementType);\r
160             }\r
161             while ((elementType = elementType.GetElementType()) != null && elementType.IsArray);\r
162         }\r
163 \r
164         private static void WritePointerType(StringBuilder typeName, Type type)\r
165         {\r
166             //\r
167             // Writes pointer type  e.g <TypeName>*\r
168             //\r
169             WriteType(typeName, type.GetElementType());\r
170             typeName.Append(PointerSymbol);\r
171         }\r
172 \r
173         private static void WriteByRefType(StringBuilder typeName, Type type)\r
174         {\r
175             //\r
176             // Writes by ref type e.g <TypeName>&\r
177             //\r
178             WriteType(typeName, type.GetElementType());\r
179             typeName.Append(ReferenceSymbol);\r
180         }\r
181 \r
182         private static void WriteArrayTypeDimensions(StringBuilder typeName, Type type)\r
183         {\r
184             //\r
185             // Writes array type dimensions e.g. [,,]\r
186             //\r
187             typeName.Append(ArrayOpeningBracket);\r
188             int rank = type.GetArrayRank();\r
189             for (int i = 1; i < rank; i++)\r
190             {\r
191                 typeName.Append(ArraySeparator);\r
192             }\r
193             typeName.Append(ArrayClosingBracket);\r
194         }\r
195 \r
196         private static void WriteGenericType(StringBuilder typeName, Type type, bool isDefinition, Queue<Type> genericTypeArguments)\r
197         {\r
198             //\r
199             // Writes generic type including parent generic types\r
200             // genericTypeArguments contains type arguments obtained from the most nested type\r
201             // isDefinition parameter indicates if we are dealing with generic type definition\r
202             //\r
203             if (type.DeclaringType != null)\r
204             {\r
205                 if (type.DeclaringType.IsGenericType)\r
206                 {\r
207                     WriteGenericType(typeName, type.DeclaringType, isDefinition, genericTypeArguments);\r
208                 }\r
209                 else\r
210                 {\r
211                     WriteNonGenericType(typeName, type.DeclaringType);\r
212                 }\r
213                 typeName.Append(NestedClassSeparator);\r
214             }\r
215             WriteGenericTypeName(typeName, type, isDefinition, genericTypeArguments);\r
216         }\r
217 \r
218         private static void WriteGenericTypeName(StringBuilder typeName, Type type, bool isDefinition, Queue<Type> genericTypeArguments)\r
219         {\r
220             //\r
221             // Writes generic type name, e.g. generic name and generic arguments\r
222             //\r
223             Assumes.IsTrue(type.IsGenericType, "Expecting type to be a generic type");\r
224             int genericArity = GetGenericArity(type);\r
225             string genericTypeName = FindGenericTypeName(type.GetGenericTypeDefinition().Name);\r
226             typeName.Append(genericTypeName);\r
227             WriteTypeArgumentsString(typeName, genericArity, isDefinition, genericTypeArguments);\r
228         }\r
229 \r
230         private static void WriteTypeArgumentsString(StringBuilder typeName, int argumentsCount, bool isDefinition, Queue<Type> genericTypeArguments)\r
231         {\r
232             //\r
233             // Writes type arguments in brackets, e.g. (<contract_name1>, <contract_name2>, ...)\r
234             //\r
235             if (argumentsCount == 0)\r
236             {\r
237                 return;\r
238             }\r
239             typeName.Append(ContractNameGenericOpeningBracket);\r
240             for (int i = 0; i < argumentsCount; i++)\r
241             {\r
242                 Assumes.IsTrue(genericTypeArguments.Count > 0, "Expecting genericTypeArguments to contain at least one Type");\r
243                 Type genericTypeArgument = genericTypeArguments.Dequeue();\r
244                 if (!isDefinition)\r
245                 {\r
246                     WriteTypeWithNamespace(typeName, genericTypeArgument);\r
247                 }\r
248                 typeName.Append(ContractNameGenericArgumentSeparator);\r
249             }\r
250             typeName.Remove(typeName.Length - 1, 1);\r
251             typeName.Append(ContractNameGenericClosingBracket);\r
252         }\r
253 \r
254         //internal for testability\r
255         internal static void WriteCustomModifiers(StringBuilder typeName, string customKeyword, Type[] types)\r
256         {\r
257             //\r
258             // Writes custom modifiers in the format: customKeyword(<contract_name>,<contract_name>,...)\r
259             //\r
260             typeName.Append(CustomModifiersSeparator);\r
261             typeName.Append(customKeyword);\r
262             Queue<Type> typeArguments = new Queue<Type>(types);\r
263             WriteTypeArgumentsString(typeName, types.Length, false, typeArguments);\r
264             Assumes.IsTrue(typeArguments.Count == 0, "Expecting genericTypeArguments queue to be empty.");\r
265         }\r
266 \r
267         private static Type FindArrayElementType(Type type)\r
268         {\r
269             //\r
270             // Gets array element type by calling GetElementType() until the element is not an array\r
271             //\r
272             Type elementType = type;\r
273             while ((elementType = elementType.GetElementType()) != null && elementType.IsArray) { }\r
274             return elementType;\r
275         }\r
276 \r
277         private static string FindGenericTypeName(string genericName)\r
278         {\r
279             //\r
280             // Gets generic type name omitting the backquote and arity indicator\r
281             // List`1 -> List\r
282             // Arity indicator is returned as output parameter\r
283             //\r
284             int indexOfBackQuote = genericName.IndexOf(GenericArityBackQuote);\r
285             if (indexOfBackQuote > -1)\r
286             {\r
287                 genericName = genericName.Substring(0, indexOfBackQuote);\r
288             }\r
289             return genericName;\r
290         }\r
291 \r
292         private static int GetGenericArity(Type type)\r
293         {\r
294             if (type.DeclaringType == null)\r
295             {\r
296                 return type.GetGenericArguments().Length;\r
297             }\r
298 \r
299             // The generic arity is equal to the difference in the number of generic arguments\r
300             // from the type and the declaring type.\r
301 \r
302             int delclaringTypeGenericArguments = type.DeclaringType.GetGenericArguments().Length;\r
303             int typeGenericArguments = type.GetGenericArguments().Length;\r
304 \r
305             Assumes.IsTrue(typeGenericArguments >= delclaringTypeGenericArguments);\r
306 \r
307             return typeGenericArguments - delclaringTypeGenericArguments;\r
308         }\r
309     }\r
310 }\r