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