Added tests for Task.WhenAll w/ empty list
[mono.git] / mcs / class / System.ServiceModel / Mono.CodeGeneration / CodeClass.cs
1 //
2 // Permission is hereby granted, free of charge, to any person obtaining
3 // a copy of this software and associated documentation files (the
4 // "Software"), to deal in the Software without restriction, including
5 // without limitation the rights to use, copy, modify, merge, publish,
6 // distribute, sublicense, and/or sell copies of the Software, and to
7 // permit persons to whom the Software is furnished to do so, subject to
8 // the following conditions:
9 // 
10 // The above copyright notice and this permission notice shall be
11 // included in all copies or substantial portions of the Software.
12 // 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 //
21 // Copyright (C) Lluis Sanchez Gual, 2004
22 //
23
24 #if !MONOTOUCH
25 using System;
26 using System.IO;
27 using System.Collections;
28 using System.Reflection;
29 using System.Reflection.Emit;
30
31 namespace Mono.CodeGeneration
32 {
33         public class CodeClass
34         {
35                 TypeBuilder typeBuilder;
36                 ArrayList customAttributes = new ArrayList ();
37                 ArrayList methods = new ArrayList ();
38                 ArrayList properties = new ArrayList ();
39                 ArrayList fields = new ArrayList ();
40                 Hashtable fieldAttributes = new Hashtable ();
41                 Type baseType;
42                 Type[] interfaces;
43                 CodeMethod ctor;
44                 CodeMethod cctor;
45                 CodeBuilder instanceInit;
46                 CodeBuilder classInit;
47                 int varId;
48                 
49                 public CodeClass (ModuleBuilder mb, string name)
50                 : this (mb, name, TypeAttributes.Public, typeof(object))
51                 {
52                 }
53                 
54                 public CodeClass (ModuleBuilder mb, string name, Type baseType, params Type[] interfaces)
55                 : this (mb, name, TypeAttributes.Public, baseType, interfaces)
56                 {
57                 }
58                 
59                 public CodeClass (ModuleBuilder mb, string name, TypeAttributes attr, Type baseType, params Type[] interfaces)
60                 {
61                         typeBuilder = mb.DefineType (name, attr, baseType, interfaces);
62                         this.baseType = baseType;
63                         this.interfaces = interfaces;
64                 }
65
66                 public CodeCustomAttribute CreateCustomAttribute (Type attributeType)
67                 {
68                         return CreateCustomAttribute (attributeType,
69                                 Type.EmptyTypes, new object [0], new string [0], new object [0]);
70                 }
71
72                 public CodeCustomAttribute CreateCustomAttribute (Type attributeType, Type [] ctorArgTypes, object [] ctorArgs, string [] namedArgFieldNames, object [] namedArgValues)
73                 {
74                         CodeCustomAttribute cca = CodeCustomAttribute.Create (
75                                 attributeType, ctorArgTypes, ctorArgs, namedArgFieldNames, namedArgValues);
76
77                         typeBuilder.SetCustomAttribute (cca.Builder);
78                         customAttributes.Add (cca);
79                         return cca;
80                 }
81
82                 public CodeCustomAttribute CreateCustomAttribute (Type attributeType, Type [] ctorArgTypes, CodeLiteral [] ctorArgs, FieldInfo [] fields, CodeLiteral [] fieldValues)
83                 {
84                         CodeCustomAttribute cca = CodeCustomAttribute.Create (
85                                 attributeType, ctorArgTypes, ctorArgs, fields, fieldValues);
86
87                         typeBuilder.SetCustomAttribute (cca.Builder);
88                         customAttributes.Add (cca);
89                         return cca;
90                 }
91
92                 public CodeProperty CreateProperty (string name, Type returnType, params Type [] parameterTypes)
93                 {
94                         return CreateProperty (name, returnType, MethodAttributes.Private, parameterTypes);
95                 }
96
97                 public CodeProperty CreateProperty (string name, Type returnType, MethodAttributes methodAttributes, params Type [] parameterTypes)
98                 {
99                         CodeProperty prop = new CodeProperty (this, GetPropertyName (name), PropertyAttributes.None, methodAttributes, returnType, parameterTypes);
100                         properties.Add (prop);
101                         return prop;
102                 }
103
104                 public CodeMethod CreateMethod (string name, Type returnType, params Type[] parameterTypes)
105                 {
106                         CodeMethod met = new CodeMethod (this, GetMethodName (name), MethodAttributes.Public, returnType, parameterTypes);
107                         methods.Add (met);
108                         return met;
109                 }
110                 
111                 public CodeMethod CreateVirtualMethod (string name, Type returnType, params Type[] parameterTypes)
112                 {
113                         CodeMethod met = new CodeMethod (this, GetMethodName (name), MethodAttributes.Public | MethodAttributes.Virtual, returnType, parameterTypes);
114                         methods.Add (met);
115                         return met;
116                 }
117                 
118                 public CodeMethod CreateStaticMethod (string name, Type returnType, params Type[] parameterTypes)
119                 {
120                         CodeMethod met = new CodeMethod (this, GetMethodName (name), MethodAttributes.Public | MethodAttributes.Static, returnType, parameterTypes);
121                         methods.Add (met);
122                         return met;
123                 }
124                 
125                 public CodeMethod CreateMethod (string name, MethodAttributes attributes, Type returnType, params Type[] parameterTypes)
126                 {
127                         CodeMethod met = new CodeMethod (this, GetMethodName (name), attributes, returnType, parameterTypes);
128                         methods.Add (met);
129                         return met;
130                 }
131                 
132                 public CodeMethod GetDefaultConstructor ()
133                 {
134                         if (ctor != null) return ctor;
135                         ctor = CreateConstructor (MethodAttributes.Public, Type.EmptyTypes);
136                         return ctor;
137                 }
138                 
139                 public CodeMethod CreateConstructor (params Type[] parameters)
140                 {
141                         return CreateConstructor (MethodAttributes.Private, parameters);
142                 }
143
144                 public CodeMethod CreateConstructor (MethodAttributes attributes, params Type[] parameters)
145                 {
146                         if (ctor != null) return ctor;
147                         ctor = CodeMethod.DefineConstructor (this, attributes, parameters);
148                         methods.Add (ctor);
149                         CodeBuilder cb = GetInstanceInitBuilder ();
150                         ctor.CodeBuilder.CurrentBlock.Add (cb.CurrentBlock);
151                         return ctor;
152                 }
153                 
154                 public CodeMethod GetStaticConstructor ()
155                 {
156                         if (cctor != null) return cctor;
157                         cctor = CodeMethod.DefineConstructor (this, MethodAttributes.Public | MethodAttributes.Static, Type.EmptyTypes);
158                         methods.Add (cctor);
159                         CodeBuilder cb = GetClassInitBuilder ();
160                         cctor.CodeBuilder.CurrentBlock.Add (cb.CurrentBlock);
161                         return cctor;
162                 }
163                 
164                 public CodeMethod ImplementMethod (Type baseType, string methodName)
165                 {
166                         MethodInfo basem = baseType.GetMethod (methodName);
167                         return ImplementMethod (baseType, basem);
168                 }
169                 
170                 public CodeMethod ImplementMethod (MethodInfo basem)
171                 {
172                         return ImplementMethod (basem.DeclaringType, basem);
173                 }
174                 
175                 public CodeMethod ImplementMethod (Type baseType, MethodInfo basem)
176                 {
177                         ParameterInfo[] pinfos = basem.GetParameters ();
178                         Type[] pars = new Type[pinfos.Length];
179                         for (int n=0; n<pinfos.Length; n++)
180                                 pars[n] = pinfos[n].ParameterType;
181
182                         CodeMethod met = CodeMethod.DefineMethod (this, basem.Name, MethodAttributes.Public | MethodAttributes.Virtual, basem.ReturnType, pars);
183                         typeBuilder.DefineMethodOverride (met.MethodInfo, basem);
184                         methods.Add (met);
185                         return met;
186                 }
187                 
188                 public CodeFieldReference DefineField (string name, Type type, params CodeCustomAttribute [] customAttributes)
189                 {
190                         return DefineField (GetFieldName (name), type, FieldAttributes.Public, null, customAttributes);
191                 }
192                 
193                 public CodeFieldReference DefineStaticField (CodeExpression initialValue, params CodeCustomAttribute [] customAttributes)
194                 {
195                         return DefineField (GetFieldName (null), initialValue.GetResultType(), FieldAttributes.Public | FieldAttributes.Static, initialValue, customAttributes);
196                 }
197                 
198                 public CodeFieldReference DefineStaticField (string name, Type type, CodeExpression initialValue, params CodeCustomAttribute [] customAttributes)
199                 {
200                         return DefineField (GetFieldName (name), type, FieldAttributes.Public | FieldAttributes.Static, initialValue, customAttributes);
201                 }
202                 
203                 public CodeFieldReference DefineField (string name, Type type, FieldAttributes attrs, CodeExpression initialValue, params CodeCustomAttribute [] customAttributes)
204                 {
205                         FieldBuilder fb = typeBuilder.DefineField (GetFieldName (name), type, attrs);
206                         foreach (CodeCustomAttribute a in customAttributes)
207                                 fb.SetCustomAttribute (a.Builder);
208                         fieldAttributes [fb] = new ArrayList (customAttributes);
209                         fields.Add (fb);
210                         CodeFieldReference fr;
211                         if ((attrs & FieldAttributes.Static) != 0)
212                                 fr = new CodeFieldReference (fb);
213                         else
214                                 fr = new CodeFieldReference (new CodeArgumentReference (TypeBuilder, 0, "this"), fb);
215                         
216                         if (null != (object) initialValue) {
217                                 CodeBuilder cb = (attrs & FieldAttributes.Static) == 0 ? GetInstanceInitBuilder () : GetClassInitBuilder (); 
218                                 cb.Assign (fr, initialValue);
219                         }
220                         return fr;
221                 }
222                 
223                 public TypeBuilder TypeBuilder
224                 {
225                         get { return typeBuilder; }
226                 } 
227                 
228                 private CodeBuilder GetInstanceInitBuilder ()
229                 {
230                         if (instanceInit != null) return instanceInit;
231                         instanceInit = new CodeBuilder (this);
232                         return instanceInit;
233                 }
234                 
235                 private CodeBuilder GetClassInitBuilder ()
236                 {
237                         if (classInit != null) return classInit;
238                         classInit = new CodeBuilder (this);
239                         return classInit;
240                 }
241                 
242                 private string GetFieldName (string name)
243                 {
244                         if (name == null) return "__field_" + (varId++);
245                         else return name;
246                 }
247                 
248                 private string GetMethodName (string name)
249                 {
250                         if (name == null) return "__Method_" + (varId++);
251                         else return name;
252                 }
253                 
254                 private string GetPropertyName (string name)
255                 {
256                         if (name == null) return "__Property_" + (varId++);
257                         else return name;
258                 }
259                 
260                 public string PrintCode ()
261                 {
262                         StringWriter sw = new StringWriter ();
263                         CodeWriter cw = new CodeWriter (sw);
264                         PrintCode (cw);
265                         return sw.ToString ();
266                 }
267                 
268                 public void PrintCode (CodeWriter cw)
269                 {
270                         for (int n=0; n<customAttributes.Count; n++) {
271                                 CodeCustomAttribute cca = customAttributes [n] as CodeCustomAttribute;
272                                 if (n > 0) cw.WriteLine ("");
273                                 cca.PrintCode (cw);
274                         }
275
276 /*                      if ((typeBuilder.Attributes & TypeAttributes.Abstract) != 0) cw.Write ("abstract ");
277                         if ((typeBuilder.Attributes & TypeAttributes.NestedAssembly) != 0) cw.Write ("internal ");
278                         if ((typeBuilder.Attributes & TypeAttributes.NestedPrivate) != 0) cw.Write ("private ");
279 */                      if ((typeBuilder.Attributes & TypeAttributes.Public) != 0) cw.Write ("public ");
280                         cw.Write ("class ").Write (typeBuilder.Name);
281                         
282                         bool dots = false;
283                         if (baseType != null && baseType != typeof(object)) {
284                                 cw.Write (" : " + baseType);
285                                 dots = true;
286                         }
287                         
288                         if (interfaces != null && interfaces.Length > 0) {
289                                 if (!dots) cw.Write (" : ");
290                                 else cw.Write (", ");
291                                 for (int n=0; n<interfaces.Length; n++) {
292                                         if (n > 0) cw.Write (", ");
293                                         cw.Write (interfaces[n].ToString ());
294                                 }
295                         }
296                         
297                         cw.EndLine ().WriteLineInd ("{");
298                         
299                         foreach (FieldInfo f in fields) {
300                                 cw.BeginLine ();
301                                 ArrayList atts = (ArrayList) fieldAttributes [f];
302                                 foreach (CodeCustomAttribute a in atts)
303                                         a.PrintCode (cw);
304                                 if ((f.Attributes & FieldAttributes.Static) != 0)
305                                         cw.Write ("static ");
306                                 cw.Write (f.FieldType.Name + " ");
307                                 cw.Write (f.Name + ";");
308                                 cw.EndLine ();
309                                 cw.WriteLine (""); 
310                         }
311                         
312                         for (int n=0; n<properties.Count; n++) {
313                                 CodeProperty prop = properties [n] as CodeProperty;
314                                 if (n > 0) cw.WriteLine ("");
315                                 prop.PrintCode (cw);
316                         }
317
318                         for (int n=0; n<methods.Count; n++) {
319                                 CodeMethod met = methods[n] as CodeMethod;
320                                 if (n > 0) cw.WriteLine ("");
321                                 met.PrintCode (cw);
322                         }
323                         cw.WriteLineUnind ("}");
324                 }
325                 
326                 public Type CreateType ()
327                 {
328                         if (ctor == null)
329                                 ctor = GetDefaultConstructor ();
330                                 
331                         foreach (CodeProperty prop in properties)
332                                 prop.Generate ();
333
334                         foreach (CodeMethod met in methods)
335                                 met.Generate ();
336                                 
337                         Type t = typeBuilder.CreateType ();
338                         
339                         foreach (CodeMethod met in methods)
340                                 met.UpdateMethodBase (t);
341                                 
342                         foreach (CodeProperty prop in properties)
343                                 prop.UpdatePropertyInfo (t);
344
345                         return t;
346                 }
347         }
348 }
349
350 #endif