Add support for custom attributes on generic type parameters.
[mono.git] / mcs / ilasm / codegen / TypeDef.cs
1 //
2 // Mono.ILASM.TypeDef
3 //
4 // Author(s):
5 //  Jackson Harper (Jackson@LatitudeGeo.com)
6 //
7 // (C) 2003 Jackson Harper, All rights reserved
8 //
9
10
11 using System;
12 using System.Collections;
13 using System.Security;
14
15 namespace Mono.ILASM {
16
17         public class TypeDef : ICustomAttrTarget, IDeclSecurityTarget, IComparable {
18
19                 protected class GenericInfo {
20                         public string Id;
21                         public int num;
22                         public ArrayList ConstraintList;
23                 }
24
25                 private PEAPI.TypeAttr attr;
26                 private string name_space;
27                 private string name;
28                 private bool is_defined;
29                 private bool is_intransit;
30                 private BaseClassRef parent;
31                 private ArrayList impl_list;
32                 private PEAPI.ClassDef classdef;
33                 private Hashtable field_table;
34                 private ArrayList field_list;
35                 private Hashtable method_table;
36                 private ArrayList customattr_list;
37                 private DeclSecurity decl_sec;
38                 private ArrayList event_list;
39                 private ArrayList property_list;
40                 private GenericParameters gen_params;
41                 private ArrayList override_list;
42                 private ArrayList override_long_list;
43                 private TypeDef outer;
44
45                 private EventDef current_event;
46                 private PropertyDef current_property;
47
48                 private int size;
49                 private int pack;
50
51                 private bool is_value_class;
52                 private bool is_enum_class;
53
54                 public TypeDef (PEAPI.TypeAttr attr, string name_space, string name,
55                                 BaseClassRef parent, ArrayList impl_list, Location location, GenericParameters gen_params, TypeDef outer)
56                 {
57                         this.attr = attr;
58                         this.parent = parent;
59                         this.impl_list = impl_list;
60                         this.gen_params = gen_params;
61                         this.outer = outer;
62
63                         field_table = new Hashtable ();
64                         field_list = new ArrayList ();
65
66                         method_table = new Hashtable ();
67
68                         size = -1;
69                         pack = -1;
70
71                         is_defined = false;
72                         is_intransit = false;
73
74                         is_value_class = false;
75                         is_enum_class = false;
76
77                         ResolveGenParams ();
78
79                         int lastdot = name.LastIndexOf ('.');
80                         /* Namespace . name split should not be done for nested classes */
81                         if (lastdot >= 0 && outer == null) {
82                                 if (name_space == null || name_space == "")
83                                         this.name_space = name.Substring (0, lastdot);
84                                 else
85                                         this.name_space = name_space + "." + name.Substring (0, lastdot);
86                                 this.name = name.Substring (lastdot + 1);
87                         } else {
88                                 this.name_space = name_space;
89                                 this.name = name;
90                         }
91                 }
92
93                 public string Name {
94                         get { return name; }
95                 }
96
97                 public string FullName {
98                         get { return MakeFullName (); }
99                 }
100
101                 public string NestedFullName {
102                         get { return (outer == null ? FullName : (outer.NestedFullName + "/" + FullName)); }
103                 }
104
105                 public TypeDef OuterType {
106                         get { return outer; }
107                 }
108
109                 public PEAPI.ClassDef PeapiType {
110                         get { return classdef; }
111                 }
112
113                 public PEAPI.ClassDef ClassDef {
114                         get { return classdef; }
115                 }
116
117                 public bool IsGenericType {
118                         get { return (gen_params == null); }
119                 }
120
121                 public bool IsDefined {
122                         get { return is_defined; }
123                 }
124
125                 public EventDef CurrentEvent {
126                         get { return current_event; }
127                 }
128
129                 public PropertyDef CurrentProperty {
130                         get { return current_property; }
131                 }
132
133                 public bool IsInterface {
134                         get { return (attr & PEAPI.TypeAttr.Interface) != 0; }
135                 }
136
137                 public GenericParameters TypeParameters {
138                         get { return gen_params; }
139                 }
140
141                 public void AddOverride (MethodDef body, BaseTypeRef parent, string name)
142                 {
143                         if (override_list == null)
144                                 override_list = new ArrayList ();
145                         override_list.Add (new DictionaryEntry (body,
146                                            new DictionaryEntry (parent, name)));
147                 }
148
149                 public void AddOverride (string sig, BaseMethodRef decl)
150                 {
151                         if (override_long_list == null)
152                                 override_long_list = new ArrayList ();
153                         override_long_list.Add (new DictionaryEntry (sig,
154                                                                 decl));
155                 }
156
157                 public void MakeValueClass ()
158                 {
159                         is_value_class = true;
160                 }
161
162                 public void MakeEnumClass ()
163                 {
164                         is_enum_class = true;
165                 }
166
167                 public void SetSize (int size)
168                 {
169                         this.size = size;
170                 }
171
172                 public void SetPack (int pack)
173                 {
174                         this.pack = pack;
175                 }
176
177                 public void AddFieldDef (FieldDef fielddef)
178                 {
179                         if (IsInterface && !fielddef.IsStatic) {
180                                 Console.WriteLine ("warning -- Non-static field in interface, set to such");
181                                 fielddef.Attributes |= PEAPI.FieldAttr.Static;
182                         }
183
184                         field_table.Add (new DictionaryEntry (fielddef.Name, fielddef.Type.FullName), fielddef);
185                         field_list.Add (fielddef);
186                 }
187
188                 public void AddMethodDef (MethodDef methoddef)
189                 {
190                         if (IsInterface && !(methoddef.IsVirtual || methoddef.IsAbstract)) {
191                                 Console.WriteLine ("warning -- Non-virtual, non-abstract instance method in interface, set to such");
192                                 methoddef.Attributes |= PEAPI.MethAttr.Abstract | PEAPI.MethAttr.Virtual;
193                         }
194
195                         method_table.Add (methoddef.Signature, methoddef);
196                 }
197
198                 public void BeginEventDef (EventDef event_def)
199                 {
200                         if (current_event != null)
201                                 throw new Exception ("An event definition was not closed.");
202
203                         current_event = event_def;
204                 }
205
206                 public void EndEventDef ()
207                 {
208                         if (event_list == null)
209                                 event_list = new ArrayList ();
210
211                         event_list.Add (current_event);
212                         current_event = null;
213                 }
214
215                 public void BeginPropertyDef (PropertyDef property_def)
216                 {
217                         if (current_property != null)
218                                 throw new Exception ("A property definition was not closed.");
219
220                         current_property = property_def;
221                 }
222
223                 public void EndPropertyDef ()
224                 {
225                         if (property_list == null)
226                                 property_list = new ArrayList ();
227
228                         property_list.Add (current_property);
229                         current_property = null;
230                 }
231
232                 public void AddCustomAttribute (CustomAttr customattr)
233                 {
234                         if (customattr_list == null)
235                                 customattr_list = new ArrayList ();
236
237                         customattr_list.Add (customattr);
238                 }
239
240                 public void AddPermissionSet (PEAPI.SecurityAction sec_action, PermissionSet ps)
241                 {
242                         if (decl_sec == null)
243                                 decl_sec = new DeclSecurity ();
244
245                         decl_sec.AddPermissionSet (sec_action, ps);
246                 }
247
248                 public void AddPermission (PEAPI.SecurityAction sec_action, IPermission iper)
249                 {
250                         if (decl_sec == null)
251                                 decl_sec = new DeclSecurity ();
252
253                         decl_sec.AddPermission (sec_action, iper);
254                 }
255
256                 public GenericParameter GetGenericParam (string id)
257                 {
258                         if (gen_params == null)
259                                 return null;
260                         
261                         return gen_params.GetGenericParam (id);
262                 }
263
264                 public GenericParameter GetGenericParam (int index)
265                 {
266                         if (gen_params == null || index < 0 || index >= gen_params.Count)
267                                 return null;
268                         
269                         return gen_params [index];
270                 }
271
272                 public int GetGenericParamNum (string id)
273                 {
274                         if (gen_params == null)
275                                 return -1;
276                         
277                         return gen_params.GetGenericParamNum (id);
278                 }
279
280                 /* Resolve any GenParams in constraints, parent & impl_list */
281                 private void ResolveGenParams ()
282                 {
283                         if (gen_params == null)
284                                 return;
285
286                         gen_params.ResolveConstraints (gen_params, null);
287
288                         BaseGenericTypeRef gtr = parent as BaseGenericTypeRef;
289                         if (gtr != null)
290                                 gtr.Resolve (gen_params, null);
291                         
292                         if (impl_list == null)
293                                 return;
294                                 
295                         foreach (BaseClassRef impl in impl_list) {
296                                 gtr = impl as BaseGenericTypeRef;
297                                 if (gtr != null)
298                                         gtr.Resolve (gen_params, null);
299                         }
300                 }
301
302                 public void Define (CodeGen code_gen)
303                 {
304                         if (is_defined)
305                                 return;
306
307                         if (is_intransit) {
308                                 // Circular definition
309                                 throw new Exception ("Circular definition of class: " + FullName);
310                         }
311
312                         if (outer != null) {
313                                 PEAPI.TypeAttr vis = attr & PEAPI.TypeAttr.VisibilityMask;
314
315                                 if (vis == PEAPI.TypeAttr.Private || vis == PEAPI.TypeAttr.Public) {
316                                         /* Nested class, but attr not set accordingly. */
317                                         //FIXME: 'report' warning here
318                                         Console.WriteLine ("Warning -- Nested class '{0}' has non-nested visibility, set to such.", NestedFullName);
319                                         attr = attr ^ vis;
320                                         attr |= (vis == PEAPI.TypeAttr.Public ? PEAPI.TypeAttr.NestedPublic : PEAPI.TypeAttr.NestedPrivate);
321                                 }               
322                         }
323                         
324                         if (parent != null) {
325                                 is_intransit = true;
326                                 parent.Resolve (code_gen);
327
328                                 is_intransit = false;
329                                 if (parent.PeapiClass == null) {
330                                         throw new Exception ("this type can not be a base type: "
331                                                         + parent);
332                                 }
333
334                                 if (parent.PeapiClass.nameSpace != null && 
335                                         parent.PeapiClass.nameSpace.CompareTo ("System") == 0) {
336                                         
337                                         if (parent.PeapiClass.name.CompareTo ("ValueType") == 0)
338                                                 is_value_class = true;
339                                         else
340                                         if (parent.PeapiClass.name.CompareTo ("Enum") == 0 )
341                                                 is_enum_class = true;          
342                                 } 
343
344                                 if (outer != null) {
345                                         if (!outer.IsDefined)
346                                                 outer.Define (code_gen);
347                                         classdef = outer.PeapiType.AddNestedClass (attr,
348                                                         name_space, name, parent.PeapiClass);
349                                 } else {
350                                         if (is_value_class || is_enum_class) {
351                                                 // Should probably confirm that the parent is System.ValueType
352                                                 classdef = code_gen.PEFile.AddValueClass (attr,
353                                                         name_space, name, is_value_class ? PEAPI.ValueClass.ValueType : PEAPI.ValueClass.Enum);
354                                         } else {
355                                                 classdef = code_gen.PEFile.AddClass (attr,
356                                                         name_space, name, parent.PeapiClass);
357                                         }
358                                 }
359                         } else {
360                                 if (outer != null) {
361                                         if (!outer.IsDefined)
362                                                 outer.Define (code_gen);
363                                         classdef = outer.PeapiType.AddNestedClass (attr,
364                                                 name_space, name);
365                                 } else {
366                                         if (is_value_class || is_enum_class) {
367                                                 classdef = code_gen.PEFile.AddValueClass (attr,
368                                                         name_space, name, is_value_class ? PEAPI.ValueClass.ValueType : PEAPI.ValueClass.Enum);
369                                         } else {
370                                                 classdef = code_gen.PEFile.AddClass (attr,
371                                                         name_space, name);
372                                         }
373                                 }
374                                 if (FullName == "System.Object")
375                                         classdef.SpecialNoSuper ();
376                         }
377
378                         is_defined = true;
379
380                         if (size != -1 || pack != -1)
381                                 classdef.AddLayoutInfo ( (pack == -1) ? 1 : pack, (size == -1) ? 0 : size);
382
383                         if (impl_list != null) {
384                                 foreach (BaseClassRef impl in impl_list) {
385                                         impl.Resolve (code_gen);
386                                         classdef.AddImplementedInterface (impl.PeapiClass);
387                                 }
388                         }
389
390                         if (gen_params != null)
391                                 gen_params.Resolve (code_gen, classdef);
392
393                         is_intransit = false;
394
395                         code_gen.AddToDefineContentsList (this);
396                 }
397
398                 public void DefineContents (CodeGen code_gen)
399                 {
400                         ArrayList fielddef_list = new ArrayList ();
401                         foreach (FieldDef fielddef in field_list) {
402                                 fielddef.Define (code_gen, classdef);
403                                 fielddef_list.Add (fielddef.PeapiFieldDef);
404                         }
405
406                         classdef.SetFieldOrder (fielddef_list);
407
408                         foreach (MethodDef methoddef in method_table.Values) {
409                                 methoddef.Define (code_gen);
410                         }
411
412                         if (event_list != null) {
413                                 foreach (EventDef eventdef in event_list) {
414                                         eventdef.Define (code_gen, classdef);
415                                 }
416                         }
417
418                         if (property_list != null) {
419                                 foreach (PropertyDef propdef in property_list) {
420                                         propdef.Define (code_gen, classdef);
421                                 }
422
423                         }
424
425                         if (customattr_list != null) {
426                                 foreach (CustomAttr customattr in customattr_list) {
427                                         customattr.AddTo (code_gen, classdef);
428                                         if (customattr.IsSuppressUnmanaged (code_gen))
429                                                 classdef.AddAttribute (PEAPI.TypeAttr.HasSecurity);
430                                 }
431                         }
432                         
433                         /// Add declarative security to this class
434                         if (decl_sec != null) {
435                                 decl_sec.AddTo (code_gen, classdef);
436                                 classdef.AddAttribute (PEAPI.TypeAttr.HasSecurity);
437                         }       
438
439                         if (override_list != null) {
440                                 foreach (DictionaryEntry entry in override_list) {
441                                         MethodDef body = (MethodDef) entry.Key;
442                                         DictionaryEntry decl = (DictionaryEntry) entry.Value;
443                                         BaseTypeRef parent_type = (BaseTypeRef) decl.Key;
444                                         parent_type.Resolve (code_gen);
445                                         string over_name = (string) decl.Value;
446                                         BaseMethodRef over_meth = parent_type.GetMethodRef (body.RetType,
447                                                         body.CallConv, over_name, body.ParamTypeList (), body.GenParamCount);
448                                         over_meth.Resolve (code_gen);
449                                         classdef.AddMethodOverride (over_meth.PeapiMethod,
450                                                         body.PeapiMethodDef);
451                                 }
452                         }
453
454                         if (override_long_list != null) {
455                                 foreach (DictionaryEntry entry in override_long_list) {
456                                         string sig = (string) entry.Key;
457                                         BaseMethodRef decl = (BaseMethodRef) entry.Value;
458                                         MethodDef body = (MethodDef) method_table[sig];
459                                         decl.Resolve (code_gen);
460                                         classdef.AddMethodOverride (decl.PeapiMethod,
461                                                         body.PeapiMethodDef);
462                                 }
463                         }
464                 }
465
466                 public PEAPI.MethodDef ResolveMethod (string signature, CodeGen code_gen)
467                 {
468                         MethodDef methoddef = (MethodDef) method_table[signature];
469
470                         if (methoddef == null) {
471                                 code_gen.Report.Error ("Unable to resolve method: " + signature);
472                                 Environment.Exit (1);
473                         }
474
475                         return methoddef.Resolve (code_gen, classdef);
476                 }
477
478                 public PEAPI.Method ResolveVarargMethod (string signature,
479                                 CodeGen code_gen, PEAPI.Type[] opt)
480                 {
481                         MethodDef methoddef = (MethodDef) method_table[signature];
482
483                         if (methoddef == null) {
484                                 code_gen.Report.Error ("Unable to resolve method: " + signature);
485                                 Environment.Exit (1);
486                         }
487
488                         methoddef.Resolve (code_gen, classdef);
489                         return methoddef.GetVarargSig (opt);
490                 }
491
492                 public PEAPI.Field ResolveField (string name, string type_name, CodeGen code_gen)
493                 {
494                         FieldDef fielddef = (FieldDef) field_table[new DictionaryEntry (name, type_name)];
495
496                         return fielddef.Resolve (code_gen, classdef);
497                 }
498
499                 private string MakeFullName ()
500                 {
501                         if (name_space == null || name_space == String.Empty)
502                                 return name;
503
504                         return name_space + "." + name;
505                 }
506
507                 public int CompareTo (object obj)
508                 {
509                         TypeDef type_def = (TypeDef) obj; 
510
511                         return FullName.CompareTo (type_def.FullName);
512                 }
513         }
514
515 }
516