0a42096dcca8877185893389d6ef07b7a841cf87
[mono.git] / mcs / mcs / interface.cs
1 //
2 // interface.cs: Interface handler
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 using System.Collections;
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace CIR {
18
19         public class Interface : DeclSpace {
20                 const MethodAttributes interface_method_attributes =
21                         MethodAttributes.Public |
22                         MethodAttributes.Abstract |
23                         MethodAttributes.HideBySig |
24                         MethodAttributes.NewSlot |
25                         MethodAttributes.Virtual;
26
27                 const MethodAttributes property_attributes =
28                         MethodAttributes.Public |
29                         MethodAttributes.Abstract |
30                         MethodAttributes.HideBySig |
31                         MethodAttributes.NewSlot |
32                         MethodAttributes.SpecialName |
33                         MethodAttributes.Virtual;
34                 
35                 ArrayList bases;
36                 int mod_flags;
37                 
38                 ArrayList defined_method;
39                 ArrayList defined_indexer;
40                 ArrayList defined_events;
41                 ArrayList defined_properties;
42                 ArrayList method_builders;
43                 
44                 TypeContainer parent;
45
46                 Attributes OptAttributes;
47                 
48                 // These will happen after the semantic analysis
49                 
50                 // Hashtable defined_indexers;
51                 // Hashtable defined_methods;
52                 
53                 // <summary>
54                 //   Modifiers allowed in a class declaration
55                 // </summary>
56                 public const int AllowedModifiers =
57                         Modifiers.NEW |
58                         Modifiers.PUBLIC |
59                         Modifiers.PROTECTED |
60                         Modifiers.INTERNAL |
61                         Modifiers.PRIVATE;
62
63                 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
64                         : base (name, l)
65                 {
66                         this.mod_flags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PUBLIC);
67                         this.parent = parent;
68                         OptAttributes = attrs;
69
70                         method_builders = new ArrayList ();
71                 }
72
73                 public AdditionResult AddMethod (InterfaceMethod imethod)
74                 {
75                         string name = imethod.Name;
76                         Object value = defined_names [name];
77
78                         if (value != null){
79                                 if (!(value is InterfaceMethod))
80                                         return AdditionResult.NameExists;
81                         } 
82
83                         if (defined_method == null)
84                                 defined_method = new ArrayList ();
85
86                         defined_method.Add (imethod);
87                         if (value == null)
88                                 DefineName (name, imethod);
89                         
90                         return AdditionResult.Success;
91                 }
92
93                 public AdditionResult AddProperty (InterfaceProperty iprop)
94                 {
95                         AdditionResult res;
96                         string name = iprop.Name;
97
98                         if ((res = IsValid (name)) != AdditionResult.Success)
99                                 return res;
100
101                         DefineName (name, iprop);
102
103                         if (defined_properties == null)
104                                 defined_properties = new ArrayList ();
105
106                         defined_properties.Add (iprop);
107                         return AdditionResult.Success;
108                 }
109
110                 public AdditionResult AddEvent (InterfaceEvent ievent)
111                 {
112                         string name = ievent.Name;
113                         AdditionResult res;
114                         
115                         if ((res = IsValid (name)) != AdditionResult.Success)
116                                 return res;
117
118                         DefineName (name, ievent);
119
120                         if (defined_events == null)
121                                 defined_events = new ArrayList ();
122
123                         defined_events.Add (ievent);
124                         return AdditionResult.Success;
125                 }
126
127                 public bool AddIndexer (InterfaceIndexer iindexer)
128                 {
129                         if (defined_indexer == null)
130                                 defined_indexer = new ArrayList ();
131                         
132                         defined_indexer.Add (iindexer);
133                         return true;
134                 }
135                 
136                 public ArrayList InterfaceMethods {
137                         get {
138                                 return defined_method;
139                         }
140                 }
141
142                 public ArrayList InterfaceProperties {
143                         get {
144                                 return defined_properties;
145                         }
146                 }
147
148                 public ArrayList InterfaceEvents {
149                         get {
150                                 return defined_events;
151                         }
152                 }
153
154                 public ArrayList InterfaceIndexers {
155                         get {
156                                 return defined_indexer;
157                         }
158                 }
159
160                 public int ModFlags {
161                         get {
162                                 return mod_flags;
163                         }
164                 }
165                 
166                 public ArrayList Bases {
167                         get {
168                                 return bases;
169                         }
170
171                         set {
172                                 bases = value;
173                         }
174                 }
175
176                 public bool IsTopLevel {
177                         get {
178                                 if (parent != null){
179                                         if (parent.Parent == null)
180                                                 return true;
181                                 }
182                                 return false;
183                         }
184                 }
185
186                 public virtual TypeAttributes InterfaceAttr {
187                         get {
188                                 TypeAttributes x = 0;
189
190                                 if ((mod_flags & Modifiers.PUBLIC) != 0)
191                                         x |= TypeAttributes.Public;
192                                 else if ((mod_flags & Modifiers.PRIVATE) != 0)
193                                         x |= TypeAttributes.NotPublic;
194                                 
195                                 if (IsTopLevel == false) {
196                                         
197                                         if ((mod_flags & Modifiers.PROTECTED) != 0
198                                             && (mod_flags & Modifiers.INTERNAL) != 0)
199                                                 x |= TypeAttributes.NestedFamORAssem;
200                                         
201                                         if ((mod_flags & Modifiers.PROTECTED) != 0)
202                                                 x |= TypeAttributes.NestedFamily;
203                                         
204                                         if ((mod_flags & Modifiers.INTERNAL) != 0)
205                                                 x |= TypeAttributes.NestedAssembly;
206                                         
207                                 }
208                                 
209                                 if ((mod_flags & Modifiers.ABSTRACT) != 0)
210                                         x |= TypeAttributes.Abstract;
211                                 
212                                 if ((mod_flags & Modifiers.SEALED) != 0)
213                                         x |= TypeAttributes.Sealed;
214
215                                 return x;
216                         }
217                 }
218                 
219                 void Error111 (InterfaceMethod im)
220                 {
221                         Report.Error (
222                                 111,
223                                 "Interface `" + Name + "' already contains a definition with the " +
224                                 "same return value and paramenter types for method `" + im.Name + "'");
225                 }
226
227                 void RegisterMethod (MethodBase mb, Type [] types)
228                 {
229                         TypeManager.RegisterMethod (mb, types);
230                         method_builders.Add (mb);
231                 }
232
233                 public MethodInfo [] GetMethods ()
234                 {
235                         int n = method_builders.Count;
236                         MethodInfo [] mi = new MethodInfo [n];
237                         
238                         method_builders.CopyTo (mi, 0);
239
240                         return mi;
241                 }
242                 
243                 //
244                 // Populates the methods in the interface
245                 //
246                 void PopulateMethod (InterfaceMethod im)
247                 {
248                         Type return_type = parent.LookupType (im.ReturnType, true);
249                         Type [] arg_types = im.ParameterTypes (parent);
250                         MethodBuilder mb;
251                         Parameter [] p;
252                         int i;
253                         
254                         //
255                         // Create the method
256                         //
257                         mb = TypeBuilder.DefineMethod (
258                                 im.Name, interface_method_attributes,
259                                 return_type, arg_types);
260                         
261                         RegisterMethod (mb, arg_types);
262                         
263                         //
264                         // Define each type attribute (in/out/ref) and
265                         // the argument names.
266                         //
267                         p = im.Parameters.FixedParameters;
268                         if (p != null){
269                                 for (i = 0; i < p.Length; i++)
270                                         mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
271
272                                 if (i != arg_types.Length)
273                                         Console.WriteLine ("Implement the type definition for params");
274                         }
275                 }
276
277                 //
278                 // Populates the properties in the interface
279                 //
280                 void PopulateProperty (InterfaceProperty ip)
281                 {
282                         PropertyBuilder pb;
283                         MethodBuilder mb;
284                         Type prop_type = parent.LookupType (ip.Type, true);
285                         Type [] setter_args = new Type [1];
286
287                         setter_args [0] = prop_type;
288
289                         //
290                         // FIXME: properties are missing the following
291                         // flags: hidebysig newslot specialname
292                         // 
293                         pb = TypeBuilder.DefineProperty (
294                                 ip.Name, PropertyAttributes.None,
295                                 prop_type, null);
296
297                         if (ip.HasGet){
298                                 mb = TypeBuilder.DefineMethod (
299                                         "get_" + ip.Name, property_attributes ,
300                                         prop_type, null);
301
302                                 //
303                                 // HACK because System.Reflection.Emit is lame
304                                 //
305                                 RegisterMethod (mb, null);
306                                 
307                                 pb.SetGetMethod (mb);
308                         }
309
310                         if (ip.HasSet){
311                                 setter_args [0] = prop_type;
312
313                                 mb = TypeBuilder.DefineMethod (
314                                         "set_" + ip.Name, property_attributes,
315                                         null, setter_args);
316
317                                 mb.DefineParameter (1, ParameterAttributes.None, "value");
318                                 pb.SetSetMethod (mb);
319
320                                 //
321                                 // HACK because System.Reflection.Emit is lame
322                                 //
323                                 RegisterMethod (mb, setter_args);
324                         }
325                 }
326
327                 //
328                 // Populates the events in the interface
329                 //
330                 void PopulateEvent (InterfaceEvent ie)
331                 {
332                         //
333                         // FIXME: We need to do this after delegates have been
334                         // declared or we declare them recursively.
335                         //
336                 }
337
338                 //
339                 // Populates the indexers in the interface
340                 //
341                 void PopulateIndexer (InterfaceIndexer ii)
342                 {
343                         PropertyBuilder pb;
344                         Type prop_type = parent.LookupType (ii.Type, true);
345                         Type [] arg_types = ii.ParameterTypes (parent);
346                         Type [] value_arg_types;
347
348                         //
349                         // Sets up the extra invisible `value' argument for setters.
350                         // 
351                         if (arg_types != null){
352                                 int count = arg_types.Length;
353                                 value_arg_types = new Type [count + 1];
354
355                                 arg_types.CopyTo (value_arg_types, 0);
356                                 value_arg_types [count] = prop_type;
357                         } else {
358                                 value_arg_types = new Type [1];
359
360                                 value_arg_types [1] = prop_type;
361                         }
362
363                         pb = TypeBuilder.DefineProperty (
364                                 "Item", PropertyAttributes.None,
365                                 prop_type, arg_types);
366
367                         if (ii.HasGet){
368                                 MethodBuilder get_item;
369                                 Parameter [] p = ii.Parameters.FixedParameters;
370                                 
371                                 get_item = TypeBuilder.DefineMethod (
372                                         "get_Item", property_attributes, prop_type, arg_types);
373                                 pb.SetGetMethod (get_item);
374                                 //
375                                 // HACK because System.Reflection.Emit is lame
376                                 //
377                                 RegisterMethod (get_item, arg_types);
378
379                                 if (p != null){
380                                         for (int i = 0; i < p.Length; i++)
381                                                 get_item.DefineParameter (
382                                                         i + 1,
383                                                         p [i].Attributes, p [i].Name);
384                                 }
385                         }
386
387                         if (ii.HasSet){
388                                 Parameter [] p = ii.Parameters.FixedParameters;
389                                 MethodBuilder set_item;
390                                 int i = 0;
391                                 
392                                 set_item = TypeBuilder.DefineMethod (
393                                         "set_Item", property_attributes, null, value_arg_types);
394                                 pb.SetSetMethod (set_item);
395                                 //
396                                 // HACK because System.Reflection.Emit is lame
397                                 //
398                                 RegisterMethod (set_item, value_arg_types);
399
400                                 if (p != null){
401                                         for (; i < p.Length; i++)
402                                                 set_item.DefineParameter (
403                                                         i + 1,
404                                                         p [i].Attributes, p [i].Name);
405                                 }
406                                 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
407                         }
408                 }
409
410                 // <summary>
411                 //   Performs the semantic analysis for all the interface members
412                 //   that were declared
413                 // </summary>
414                 bool SemanticAnalysis ()
415                 {
416                         Hashtable methods = new Hashtable ();
417
418                         
419                         if (defined_method != null){
420                                 foreach (InterfaceMethod im in defined_method){
421                                         string sig = im.GetSignature (parent);
422                                         
423                                         //
424                                         // If there was an undefined Type on the signatures
425                                         // 
426                                         if (sig == null)
427                                                 continue;
428                                         
429                                         if (methods [sig] != null){
430                                                 Error111 (im);
431                                                 return false;
432                                         }
433                                 }
434                         }
435
436                         //
437                         // FIXME: Here I should check i
438                         // 
439                         return true;
440                 }
441
442                 // <summary>
443                 //   Performs semantic analysis, and then generates the IL interfaces
444                 // </summary>
445                 public void Populate ()
446                 {
447                         if (!SemanticAnalysis ())
448                                 return;
449
450                         if (defined_method != null){
451                                 foreach (InterfaceMethod im in defined_method)
452                                         PopulateMethod (im);
453                         }
454
455                         if (defined_properties != null){
456                                 foreach (InterfaceProperty ip in defined_properties)
457                                         PopulateProperty (ip);
458                         }
459
460                         if (defined_events != null)
461                                 foreach (InterfaceEvent ie in defined_events)
462                                         PopulateEvent (ie);
463
464                         if (defined_indexer != null)
465                                 foreach (InterfaceIndexer ii in defined_indexer)
466                                         PopulateIndexer (ii);
467                 }
468         }
469
470         public class InterfaceMemberBase {
471                 public readonly string Name;
472                 public readonly bool IsNew;
473                 public Attributes OptAttributes;
474                 
475                 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
476                 {
477                         Name = name;
478                         IsNew = is_new;
479                         OptAttributes = attrs;
480                 }
481         }
482         
483         public class InterfaceProperty : InterfaceMemberBase {
484                 public readonly bool HasSet;
485                 public readonly bool HasGet;
486                 public readonly string Type;
487                 public readonly string type;
488                 
489                 public InterfaceProperty (string type, string name,
490                                           bool is_new, bool has_get, bool has_set, Attributes attrs)
491                         : base (name, is_new, attrs)
492                 {
493                         Type = type;
494                         HasGet = has_get;
495                         HasSet = has_set;
496                 }
497         }
498
499         public class InterfaceEvent : InterfaceMemberBase {
500                 public readonly string Type;
501                 
502                 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
503                         : base (name, is_new, attrs)
504                 {
505                         Type = type;
506                 }
507         }
508         
509         public class InterfaceMethod : InterfaceMemberBase {
510                 public readonly string     ReturnType;
511                 public readonly Parameters Parameters;
512                 
513                 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args, Attributes attrs)
514                         : base (name, is_new, attrs)
515                 {
516                         this.ReturnType = return_type;
517                         this.Parameters = args;
518                 }
519
520                 // <summary>
521                 //   Returns the signature for this interface method
522                 // </summary>
523                 public string GetSignature (TypeContainer tc)
524                 {
525                         Type ret = tc.LookupType (ReturnType, false);
526                         string args = Parameters.GetSignature (tc);
527
528                         if ((ret == null) || (args == null))
529                                 return null;
530                         
531                         return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
532                 }
533
534                 public Type [] ParameterTypes (TypeContainer tc)
535                 {
536                         return Parameters.GetParameterInfo (tc);
537                 }
538         }
539
540         public class InterfaceIndexer : InterfaceMemberBase {
541                 public readonly bool HasGet, HasSet;
542                 public readonly Parameters Parameters;
543                 public readonly string Type;
544                 
545                 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set, bool is_new,
546                                          Attributes attrs)
547                         : base ("", is_new, attrs)
548                 {
549                         Type = type;
550                         Parameters = args;
551                         HasGet = do_get;
552                         HasSet = do_set;
553                 }
554
555                 public Type [] ParameterTypes (TypeContainer tc)
556                 {
557                         return Parameters.GetParameterInfo (tc);
558                 }
559         }
560 }