2 // interface.cs: Interface handler
4 // Author: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
11 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
17 namespace Mono.CSharp {
22 public class Interface : DeclSpace {
23 const MethodAttributes interface_method_attributes =
24 MethodAttributes.Public |
25 MethodAttributes.Abstract |
26 MethodAttributes.HideBySig |
27 MethodAttributes.NewSlot |
28 MethodAttributes.Virtual;
30 const MethodAttributes property_attributes =
31 MethodAttributes.Public |
32 MethodAttributes.Abstract |
33 MethodAttributes.HideBySig |
34 MethodAttributes.NewSlot |
35 MethodAttributes.SpecialName |
36 MethodAttributes.Virtual;
40 ArrayList defined_method;
41 ArrayList defined_indexer;
42 ArrayList defined_events;
43 ArrayList defined_properties;
45 ArrayList method_builders;
46 ArrayList property_builders;
47 ArrayList event_builders;
49 Attributes OptAttributes;
51 public string IndexerName;
53 // These will happen after the semantic analysis
55 // Hashtable defined_indexers;
56 // Hashtable defined_methods;
59 /// Modifiers allowed in a class declaration
61 public const int AllowedModifiers =
69 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
70 : base (parent, name, l)
72 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
73 OptAttributes = attrs;
75 method_builders = new ArrayList ();
76 property_builders = new ArrayList ();
77 event_builders = new ArrayList ();
80 public AdditionResult AddMethod (InterfaceMethod imethod)
82 string name = imethod.Name;
83 Object value = defined_names [name];
86 if (!(value is InterfaceMethod))
87 return AdditionResult.NameExists;
90 if (defined_method == null)
91 defined_method = new ArrayList ();
93 defined_method.Add (imethod);
95 DefineName (name, imethod);
97 return AdditionResult.Success;
100 public AdditionResult AddProperty (InterfaceProperty iprop)
103 string name = iprop.Name;
105 if ((res = IsValid (name)) != AdditionResult.Success)
108 DefineName (name, iprop);
110 if (defined_properties == null)
111 defined_properties = new ArrayList ();
113 defined_properties.Add (iprop);
114 return AdditionResult.Success;
117 public AdditionResult AddEvent (InterfaceEvent ievent)
119 string name = ievent.Name;
122 if ((res = IsValid (name)) != AdditionResult.Success)
125 DefineName (name, ievent);
127 if (defined_events == null)
128 defined_events = new ArrayList ();
130 defined_events.Add (ievent);
131 return AdditionResult.Success;
134 public bool AddIndexer (InterfaceIndexer iindexer)
136 if (defined_indexer == null)
137 defined_indexer = new ArrayList ();
139 defined_indexer.Add (iindexer);
143 public ArrayList InterfaceMethods {
145 return defined_method;
149 public ArrayList InterfaceProperties {
151 return defined_properties;
155 public ArrayList InterfaceEvents {
157 return defined_events;
161 public ArrayList InterfaceIndexers {
163 return defined_indexer;
167 public ArrayList Bases {
177 public virtual TypeAttributes InterfaceAttr {
179 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
181 if (IsTopLevel == false) {
183 if ((ModFlags & Modifiers.PROTECTED) != 0
184 && (ModFlags & Modifiers.INTERNAL) != 0)
185 x |= TypeAttributes.NestedFamORAssem;
186 else if ((ModFlags & Modifiers.PROTECTED) != 0)
187 x |= TypeAttributes.NestedFamily;
188 else if ((ModFlags & Modifiers.INTERNAL) != 0)
189 x |= TypeAttributes.NestedAssembly;
190 else if ((ModFlags & Modifiers.PUBLIC) != 0)
191 x |= TypeAttributes.NestedPublic;
193 x |= TypeAttributes.NestedPrivate;
195 if ((ModFlags & Modifiers.PUBLIC) != 0)
196 x |= TypeAttributes.Public;
197 else if ((ModFlags & Modifiers.PRIVATE) != 0)
198 x |= TypeAttributes.NotPublic;
201 if ((ModFlags & Modifiers.ABSTRACT) != 0)
202 x |= TypeAttributes.Abstract;
204 if ((ModFlags & Modifiers.SEALED) != 0)
205 x |= TypeAttributes.Sealed;
211 void Error111 (InterfaceMemberBase ib)
215 "Interface `" + Name + "' already contains a definition with the " +
216 "same return value and parameter types for member `" + ib.Name + "'");
219 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
221 if (!TypeManager.RegisterMethod (mb, ip, types))
224 method_builders.Add (mb);
228 public MethodInfo [] GetMethods ()
230 int n = method_builders.Count;
231 MethodInfo [] mi = new MethodInfo [n];
233 method_builders.CopyTo (mi, 0);
238 // Hack around System.Reflection as found everywhere else
239 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
241 ArrayList members = new ArrayList ();
243 if ((mt & MemberTypes.Method) != 0) {
244 foreach (MethodBuilder mb in method_builders)
245 if (filter (mb, criteria))
249 if ((mt & MemberTypes.Property) != 0) {
250 foreach (PropertyBuilder pb in property_builders)
251 if (filter (pb, criteria))
255 if ((mt & MemberTypes.Event) != 0) {
256 foreach (MyEventBuilder eb in event_builders)
257 if (filter (eb, criteria))
261 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
262 MemberInfo [] parent_mi;
264 parent_mi = TypeContainer.FindMembers (
265 TypeBuilder.BaseType, mt, bf, filter, criteria);
267 if (parent_mi != null)
268 members.AddRange (parent_mi);
271 // The rest of the cases, if any, are unhandled at present.
273 int count = members.Count;
276 MemberInfo [] mi = new MemberInfo [count];
277 members.CopyTo (mi, 0);
285 // Populates the methods in the interface
287 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
289 Type return_type = this.ResolveType (im.ReturnType, false, im.Location);
290 Type [] arg_types = im.ParameterTypes (this);
295 if (return_type == null)
298 if (return_type.IsPointer && !UnsafeOK (this))
301 foreach (Type t in arg_types){
306 if (t.IsPointer && !UnsafeOK (this))
313 mb = TypeBuilder.DefineMethod (
314 im.Name, interface_method_attributes,
315 return_type, arg_types);
317 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
319 if (!RegisterMethod (mb, ip, arg_types)) {
325 // Define each type attribute (in/out/ref) and
326 // the argument names.
328 p = im.Parameters.FixedParameters;
330 for (i = 0; i < p.Length; i++)
331 mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
333 if (i != arg_types.Length)
334 Console.WriteLine ("Implement the type definition for params");
337 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
338 return_type, ModFlags, false);
340 if (im.OptAttributes != null)
341 Attribute.ApplyAttributes (ec, mb, im, im.OptAttributes, Location);
345 // Populates the properties in the interface
347 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
350 MethodBuilder get = null, set = null;
351 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
352 Type prop_type = ip.Type.Type;
353 Type [] setter_args = new Type [1];
355 if (prop_type == null)
358 if (prop_type.IsPointer && !UnsafeOK (this))
361 setter_args [0] = prop_type;
364 // FIXME: properties are missing the following
365 // flags: hidebysig newslot specialname
367 pb = TypeBuilder.DefineProperty (
368 ip.Name, PropertyAttributes.None,
372 get = TypeBuilder.DefineMethod (
373 "get_" + ip.Name, property_attributes ,
377 // HACK because System.Reflection.Emit is lame
379 Type [] null_types = null;
380 InternalParameters inp = new InternalParameters
381 (null_types, Parameters.EmptyReadOnlyParameters);
383 if (!RegisterMethod (get, inp, null)) {
388 pb.SetGetMethod (get);
392 setter_args [0] = prop_type;
394 set = TypeBuilder.DefineMethod (
395 "set_" + ip.Name, property_attributes,
396 TypeManager.void_type, setter_args);
398 set.DefineParameter (1, ParameterAttributes.None, "value");
399 pb.SetSetMethod (set);
402 // HACK because System.Reflection.Emit is lame
404 Parameter [] parms = new Parameter [1];
405 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
406 InternalParameters ipp = new InternalParameters (
407 this, new Parameters (parms, null, Location.Null));
409 if (!RegisterMethod (set, ipp, setter_args)) {
415 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
416 null, ModFlags, false);
418 if (ip.OptAttributes != null)
419 Attribute.ApplyAttributes (ec, pb, ip, ip.OptAttributes, Location);
421 TypeManager.RegisterProperty (pb, get, set);
422 property_builders.Add (pb);
426 // Populates the events in the interface
428 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
431 // FIXME: We need to do this after delegates have been
432 // declared or we declare them recursively.
435 MethodBuilder add = null, remove = null;
436 ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
437 Type event_type = ie.Type.Type;
439 if (event_type == null)
442 if (event_type.IsPointer && !UnsafeOK (this))
445 Type [] parameters = new Type [1];
446 parameters [0] = event_type;
448 eb = new MyEventBuilder (TypeBuilder, ie.Name,
449 EventAttributes.None, event_type);
452 // Now define the accessors
454 string add_name = "add_" + ie.Name;
456 add = TypeBuilder.DefineMethod (
457 add_name, property_attributes, null, parameters);
458 add.DefineParameter (1, ParameterAttributes.None, "value");
459 eb.SetAddOnMethod (add);
461 string remove_name = "remove_" + ie.Name;
462 remove = TypeBuilder.DefineMethod (
463 remove_name, property_attributes, null, parameters);
464 remove.DefineParameter (1, ParameterAttributes.None, "value");
465 eb.SetRemoveOnMethod (remove);
467 Parameter [] parms = new Parameter [1];
468 parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
469 InternalParameters ip = new InternalParameters (
470 this, new Parameters (parms, null, Location.Null));
472 if (!RegisterMethod (add, ip, parameters)) {
477 if (!RegisterMethod (remove, ip, parameters)) {
482 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
483 null, ModFlags, false);
486 if (ie.OptAttributes != null)
487 Attribute.ApplyAttributes (ec, eb, ie, ie.OptAttributes, Location);
489 TypeManager.RegisterEvent (eb, add, remove);
490 event_builders.Add (eb);
494 // Populates the indexers in the interface
496 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
499 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
500 Type prop_type = ii.Type.Type;
501 Type [] arg_types = ii.ParameterTypes (this);
502 Type [] value_arg_types;
504 if (prop_type == null)
507 if (prop_type.IsPointer && !UnsafeOK (this))
511 // Sets up the extra invisible `value' argument for setters.
513 if (arg_types != null){
514 int count = arg_types.Length;
515 value_arg_types = new Type [count + 1];
517 arg_types.CopyTo (value_arg_types, 0);
518 value_arg_types [count] = prop_type;
520 foreach (Type t in arg_types){
521 if (t.IsPointer && !UnsafeOK (this))
525 value_arg_types = new Type [1];
527 value_arg_types [1] = prop_type;
530 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
531 null, ModFlags, false);
533 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
534 if (IndexerName == null)
535 IndexerName = "Item";
537 pb = TypeBuilder.DefineProperty (
538 IndexerName, PropertyAttributes.None,
539 prop_type, arg_types);
541 MethodBuilder set_item = null, get_item = null;
543 Parameter [] p = ii.Parameters.FixedParameters;
545 get_item = TypeBuilder.DefineMethod (
546 "get_" + IndexerName, property_attributes,
547 prop_type, arg_types);
548 pb.SetGetMethod (get_item);
550 // HACK because System.Reflection.Emit is lame
552 InternalParameters ip = new InternalParameters (
553 arg_types, ii.Parameters);
555 if (!RegisterMethod (get_item, ip, arg_types)) {
561 for (int i = 0; i < p.Length; i++)
562 get_item.DefineParameter (
564 p [i].Attributes, p [i].Name);
569 Parameter [] p = ii.Parameters.FixedParameters;
573 pv = new Parameter [p.Length + 1];
575 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
576 Parameters value_params = new Parameters (pv, null, Location.Null);
577 value_params.GetParameterInfo (decl_space);
579 set_item = TypeBuilder.DefineMethod (
580 "set_" + IndexerName, property_attributes,
581 TypeManager.void_type, value_arg_types);
582 pb.SetSetMethod (set_item);
584 // HACK because System.Reflection.Emit is lame
586 InternalParameters ip = new InternalParameters (
587 value_arg_types, value_params);
588 if (!RegisterMethod (set_item, ip, value_arg_types)) {
594 for (; i < p.Length; i++)
595 set_item.DefineParameter (
597 p [i].Attributes, p [i].Name);
600 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
603 if (ii.OptAttributes != null)
604 Attribute.ApplyAttributes (ec, pb, ii, ii.OptAttributes, Location);
606 property_builders.Add (pb);
610 /// Performs the semantic analysis for all the interface members
611 /// that were declared
613 bool SemanticAnalysis ()
615 Hashtable methods = new Hashtable ();
618 if (defined_method != null){
619 foreach (InterfaceMethod im in defined_method){
620 string sig = im.GetSignature (this);
623 // If there was an undefined Type on the signatures
628 if (methods [sig] != null){
636 // FIXME: Here I should check i
641 Type GetInterfaceTypeByName (string name)
643 Type t = FindType (name);
646 Report.Error (246, Location, "The type or namespace `" + name +
647 "' could not be found");
657 cause = "is a struct";
659 cause = "is a class";
661 cause = "Should not happen.";
663 Report.Error (527, Location, "`"+name+"' " + cause +
664 ", need an interface instead");
670 // Returns the list of interfaces that this interface implements
671 // Or null if it does not implement any interface.
673 // Sets the error boolean accoringly.
675 Type [] GetInterfaceBases (out bool error)
684 tbases = new Type [Bases.Count];
687 foreach (string name in Bases){
690 t = GetInterfaceTypeByName (name);
696 if (!Parent.AsAccessible (t, ModFlags))
697 Report.Error (61, Location,
698 "Inconsistent accessibility: base interface `" +
699 TypeManager.CSharpName (t) + "' is less " +
700 "accessible than interface `" +
706 return TypeManager.ExpandInterfaces (tbases);
711 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
715 // Rework the way we recurse, because for recursive
716 // definitions of interfaces (A:B and B:A) we report the
717 // error twice, rather than once.
719 public override TypeBuilder DefineType ()
724 if (TypeBuilder != null)
732 ifaces = GetInterfaceBases (out error);
738 ModuleBuilder builder = CodeGen.ModuleBuilder;
740 TypeBuilder = builder.DefineType (
743 (Type)null, // Parent Type
745 RootContext.RegisterOrder (this);
747 TypeBuilder builder = Parent.TypeBuilder;
749 TypeBuilder = builder.DefineNestedType (
752 (Type) null, //parent type
755 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
756 tc.RegisterOrder (this);
759 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
766 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
767 // interface is consistent. Either it is `Item' or it is the name defined by all the
768 // indexers with the `IndexerName' attribute.
770 // Turns out that the IndexerNameAttribute is applied to each indexer,
771 // but it is never emitted, instead a DefaultName attribute is attached
774 void DefineIndexers (TypeContainer parent)
776 string interface_indexer_name = null;
778 foreach (InterfaceIndexer ii in defined_indexer){
780 PopulateIndexer (parent, this, ii);
782 if (interface_indexer_name == null){
783 interface_indexer_name = IndexerName;
787 if (IndexerName == interface_indexer_name)
791 668, "Two indexers have different names, " +
792 " you should use the same name for all your indexers");
794 if (interface_indexer_name == null)
795 interface_indexer_name = "Item";
796 IndexerName = interface_indexer_name;
800 /// Performs semantic analysis, and then generates the IL interfaces
802 public override bool Define (TypeContainer parent)
804 if (!SemanticAnalysis ())
807 if (defined_method != null){
808 foreach (InterfaceMethod im in defined_method)
809 PopulateMethod (parent, this, im);
812 if (defined_properties != null){
813 foreach (InterfaceProperty ip in defined_properties)
814 PopulateProperty (parent, this, ip);
817 if (defined_events != null)
818 foreach (InterfaceEvent ie in defined_events)
819 PopulateEvent (parent, this, ie);
821 if (defined_indexer != null) {
822 DefineIndexers (parent);
824 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
825 parent, IndexerName, ModFlags, Location);
827 TypeBuilder.SetCustomAttribute (cb);
833 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
838 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
840 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
841 ".ctor", MemberTypes.Constructor,
842 BindingFlags.Public | BindingFlags.Instance,
845 if (!(ml is MethodGroupExpr)) {
846 Console.WriteLine ("Internal error !!!!");
850 MethodGroupExpr mg = (MethodGroupExpr) ml;
852 MethodBase constructor = mg.Methods [0];
854 string [] vals = { name };
856 CustomAttributeBuilder cb = null;
858 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
860 Report.Warning (-100, "Can not set the indexer default member attribute");
868 public class InterfaceMemberBase {
869 public readonly string Name;
870 public readonly bool IsNew;
871 public Attributes OptAttributes;
873 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
877 OptAttributes = attrs;
881 public class InterfaceProperty : InterfaceMemberBase {
882 public readonly bool HasSet;
883 public readonly bool HasGet;
884 public readonly Location Location;
885 public Expression Type;
887 public InterfaceProperty (Expression type, string name,
888 bool is_new, bool has_get, bool has_set,
889 Attributes attrs, Location loc)
890 : base (name, is_new, attrs)
899 public class InterfaceEvent : InterfaceMemberBase {
900 public readonly Location Location;
901 public Expression Type;
903 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
905 : base (name, is_new, attrs)
912 public class InterfaceMethod : InterfaceMemberBase {
913 public readonly Expression ReturnType;
914 public readonly Parameters Parameters;
915 public readonly Location Location;
917 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
918 Attributes attrs, Location l)
919 : base (name, is_new, attrs)
921 this.ReturnType = return_type;
922 this.Parameters = args;
927 /// Returns the signature for this interface method
929 public string GetSignature (DeclSpace ds)
931 Type ret = ds.ResolveType (ReturnType, false, Location);
932 string args = Parameters.GetSignature (ds);
934 if ((ret == null) || (args == null))
937 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
940 public Type [] ParameterTypes (DeclSpace ds)
942 return Parameters.GetParameterInfo (ds);
946 public class InterfaceIndexer : InterfaceMemberBase {
947 public readonly bool HasGet, HasSet;
948 public readonly Parameters Parameters;
949 public readonly Location Location;
950 public Expression Type;
952 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
953 bool is_new, Attributes attrs, Location loc)
954 : base ("", is_new, attrs)
963 public Type [] ParameterTypes (DeclSpace ds)
965 return Parameters.GetParameterInfo (ds);