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;
48 Attributes OptAttributes;
50 // These will happen after the semantic analysis
52 // Hashtable defined_indexers;
53 // Hashtable defined_methods;
56 /// Modifiers allowed in a class declaration
58 public const int AllowedModifiers =
66 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
67 : base (parent, name, l)
69 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
70 OptAttributes = attrs;
72 method_builders = new ArrayList ();
73 property_builders = new ArrayList ();
76 public AdditionResult AddMethod (InterfaceMethod imethod)
78 string name = imethod.Name;
79 Object value = defined_names [name];
82 if (!(value is InterfaceMethod))
83 return AdditionResult.NameExists;
86 if (defined_method == null)
87 defined_method = new ArrayList ();
89 defined_method.Add (imethod);
91 DefineName (name, imethod);
93 return AdditionResult.Success;
96 public AdditionResult AddProperty (InterfaceProperty iprop)
99 string name = iprop.Name;
101 if ((res = IsValid (name)) != AdditionResult.Success)
104 DefineName (name, iprop);
106 if (defined_properties == null)
107 defined_properties = new ArrayList ();
109 defined_properties.Add (iprop);
110 return AdditionResult.Success;
113 public AdditionResult AddEvent (InterfaceEvent ievent)
115 string name = ievent.Name;
118 if ((res = IsValid (name)) != AdditionResult.Success)
121 DefineName (name, ievent);
123 if (defined_events == null)
124 defined_events = new ArrayList ();
126 defined_events.Add (ievent);
127 return AdditionResult.Success;
130 public bool AddIndexer (InterfaceIndexer iindexer)
132 if (defined_indexer == null)
133 defined_indexer = new ArrayList ();
135 defined_indexer.Add (iindexer);
139 public ArrayList InterfaceMethods {
141 return defined_method;
145 public ArrayList InterfaceProperties {
147 return defined_properties;
151 public ArrayList InterfaceEvents {
153 return defined_events;
157 public ArrayList InterfaceIndexers {
159 return defined_indexer;
163 public ArrayList Bases {
173 public virtual TypeAttributes InterfaceAttr {
175 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
177 if (IsTopLevel == false) {
179 if ((ModFlags & Modifiers.PROTECTED) != 0
180 && (ModFlags & Modifiers.INTERNAL) != 0)
181 x |= TypeAttributes.NestedFamORAssem;
182 else if ((ModFlags & Modifiers.PROTECTED) != 0)
183 x |= TypeAttributes.NestedFamily;
184 else if ((ModFlags & Modifiers.INTERNAL) != 0)
185 x |= TypeAttributes.NestedAssembly;
186 else if ((ModFlags & Modifiers.PUBLIC) != 0)
187 x |= TypeAttributes.NestedPublic;
189 x |= TypeAttributes.NestedPrivate;
191 if ((ModFlags & Modifiers.PUBLIC) != 0)
192 x |= TypeAttributes.Public;
193 else if ((ModFlags & Modifiers.PRIVATE) != 0)
194 x |= TypeAttributes.NotPublic;
197 if ((ModFlags & Modifiers.ABSTRACT) != 0)
198 x |= TypeAttributes.Abstract;
200 if ((ModFlags & Modifiers.SEALED) != 0)
201 x |= TypeAttributes.Sealed;
207 void Error111 (InterfaceMemberBase ib)
211 "Interface `" + Name + "' already contains a definition with the " +
212 "same return value and parameter types for member `" + ib.Name + "'");
215 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
217 if (!TypeManager.RegisterMethod (mb, ip, types))
220 method_builders.Add (mb);
224 public MethodInfo [] GetMethods ()
226 int n = method_builders.Count;
227 MethodInfo [] mi = new MethodInfo [n];
229 method_builders.CopyTo (mi, 0);
234 // Hack around System.Reflection as found everywhere else
235 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
237 ArrayList members = new ArrayList ();
239 if ((mt & MemberTypes.Method) != 0) {
240 foreach (MethodBuilder mb in method_builders)
241 if (filter (mb, criteria))
245 if ((mt & MemberTypes.Property) != 0) {
246 foreach (PropertyBuilder pb in property_builders)
247 if (filter (pb, criteria))
251 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
252 MemberInfo [] parent_mi;
254 parent_mi = TypeContainer.FindMembers (
255 TypeBuilder.BaseType, mt, bf, filter, criteria);
257 if (parent_mi != null)
258 members.AddRange (parent_mi);
261 // The rest of the cases, if any, are unhandled at present.
263 int count = members.Count;
266 MemberInfo [] mi = new MemberInfo [count];
267 members.CopyTo (mi, 0);
275 // Populates the methods in the interface
277 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
279 Type return_type = RootContext.LookupType (this, im.ReturnType, false, im.Location);
280 Type [] arg_types = im.ParameterTypes (this);
285 if (return_type == null)
288 if (return_type.IsPointer && !UnsafeOK (this))
291 foreach (Type t in arg_types){
296 if (t.IsPointer && !UnsafeOK (this))
303 mb = TypeBuilder.DefineMethod (
304 im.Name, interface_method_attributes,
305 return_type, arg_types);
307 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
309 if (!RegisterMethod (mb, ip, arg_types)) {
315 // Define each type attribute (in/out/ref) and
316 // the argument names.
318 p = im.Parameters.FixedParameters;
320 for (i = 0; i < p.Length; i++)
321 mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
323 if (i != arg_types.Length)
324 Console.WriteLine ("Implement the type definition for params");
327 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
328 return_type, ModFlags, false);
330 if (im.OptAttributes != null)
331 Attribute.ApplyAttributes (ec, mb, im, im.OptAttributes, Location);
335 // Populates the properties in the interface
337 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
340 MethodBuilder get = null, set = null;
341 Type prop_type = RootContext.LookupType (this, ip.Type, false, ip.Location);
342 Type [] setter_args = new Type [1];
344 if (prop_type == null)
347 if (prop_type.IsPointer && !UnsafeOK (this))
350 setter_args [0] = prop_type;
353 // FIXME: properties are missing the following
354 // flags: hidebysig newslot specialname
356 pb = TypeBuilder.DefineProperty (
357 ip.Name, PropertyAttributes.None,
361 get = TypeBuilder.DefineMethod (
362 "get_" + ip.Name, property_attributes ,
366 // HACK because System.Reflection.Emit is lame
368 Type [] null_types = null;
369 InternalParameters inp = new InternalParameters
370 (null_types, Parameters.GetEmptyReadOnlyParameters ());
372 if (!RegisterMethod (get, inp, null)) {
377 pb.SetGetMethod (get);
381 setter_args [0] = prop_type;
383 set = TypeBuilder.DefineMethod (
384 "set_" + ip.Name, property_attributes,
385 TypeManager.void_type, setter_args);
387 set.DefineParameter (1, ParameterAttributes.None, "value");
388 pb.SetSetMethod (set);
391 // HACK because System.Reflection.Emit is lame
393 Parameter [] parms = new Parameter [1];
394 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
395 InternalParameters ipp = new InternalParameters (
396 this, new Parameters (parms, null, Location.Null));
398 if (!RegisterMethod (set, ipp, setter_args)) {
404 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
405 null, ModFlags, false);
407 if (ip.OptAttributes != null)
408 Attribute.ApplyAttributes (ec, pb, ip, ip.OptAttributes, Location);
410 TypeManager.RegisterProperty (pb, get, set);
411 property_builders.Add (pb);
415 // Populates the events in the interface
417 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
420 // FIXME: We need to do this after delegates have been
421 // declared or we declare them recursively.
426 // Populates the indexers in the interface
428 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
431 Type prop_type = RootContext.LookupType (this, ii.Type, false, ii.Location);
432 Type [] arg_types = ii.ParameterTypes (this);
433 Type [] value_arg_types;
435 if (prop_type == null)
438 if (prop_type.IsPointer && !UnsafeOK (this))
442 // Sets up the extra invisible `value' argument for setters.
444 if (arg_types != null){
445 int count = arg_types.Length;
446 value_arg_types = new Type [count + 1];
448 arg_types.CopyTo (value_arg_types, 0);
449 value_arg_types [count] = prop_type;
451 foreach (Type t in arg_types){
452 if (t.IsPointer && !UnsafeOK (this))
456 value_arg_types = new Type [1];
458 value_arg_types [1] = prop_type;
461 pb = TypeBuilder.DefineProperty (
462 "Item", PropertyAttributes.None,
463 prop_type, arg_types);
465 MethodBuilder set_item = null, get_item = null;
467 Parameter [] p = ii.Parameters.FixedParameters;
469 get_item = TypeBuilder.DefineMethod (
470 "get_Item", property_attributes, prop_type, arg_types);
471 pb.SetGetMethod (get_item);
473 // HACK because System.Reflection.Emit is lame
475 InternalParameters ip = new InternalParameters (
476 arg_types, ii.Parameters);
478 if (!RegisterMethod (get_item, ip, arg_types)) {
484 for (int i = 0; i < p.Length; i++)
485 get_item.DefineParameter (
487 p [i].Attributes, p [i].Name);
492 Parameter [] p = ii.Parameters.FixedParameters;
496 pv = new Parameter [p.Length + 1];
498 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
499 Parameters value_params = new Parameters (pv, null, Location.Null);
500 value_params.GetParameterInfo (decl_space);
502 set_item = TypeBuilder.DefineMethod (
503 "set_Item", property_attributes,
504 TypeManager.void_type, value_arg_types);
505 pb.SetSetMethod (set_item);
507 // HACK because System.Reflection.Emit is lame
509 InternalParameters ip = new InternalParameters (
510 value_arg_types, value_params);
511 if (!RegisterMethod (set_item, ip, value_arg_types)) {
517 for (; i < p.Length; i++)
518 set_item.DefineParameter (
520 p [i].Attributes, p [i].Name);
523 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
526 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
527 null, ModFlags, false);
529 if (ii.OptAttributes != null)
530 Attribute.ApplyAttributes (ec, pb, ii, ii.OptAttributes, Location);
532 property_builders.Add (pb);
536 /// Performs the semantic analysis for all the interface members
537 /// that were declared
539 bool SemanticAnalysis ()
541 Hashtable methods = new Hashtable ();
544 if (defined_method != null){
545 foreach (InterfaceMethod im in defined_method){
546 string sig = im.GetSignature (this);
549 // If there was an undefined Type on the signatures
554 if (methods [sig] != null){
562 // FIXME: Here I should check i
567 Type GetInterfaceTypeByName (string name)
569 Type t = FindType (name);
580 cause = "is a struct";
582 cause = "is a class";
584 cause = "Should not happen.";
586 Report.Error (527, Location, "`"+name+"' " + cause +
587 ", need an interface instead");
593 // Returns the list of interfaces that this interface implements
594 // Or null if it does not implement any interface.
596 // Sets the error boolean accoringly.
598 Type [] GetInterfaceBases (out bool error)
607 tbases = new Type [Bases.Count];
610 foreach (string name in Bases){
613 t = GetInterfaceTypeByName (name);
622 return TypeManager.ExpandInterfaces (tbases);
627 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
631 // Rework the way we recurse, because for recursive
632 // definitions of interfaces (A:B and B:A) we report the
633 // error twice, rather than once.
635 public override TypeBuilder DefineType ()
640 if (TypeBuilder != null)
648 ifaces = GetInterfaceBases (out error);
654 ModuleBuilder builder = CodeGen.ModuleBuilder;
656 TypeBuilder = builder.DefineType (
659 (Type)null, // Parent Type
661 RootContext.RegisterOrder (this);
663 TypeBuilder builder = Parent.TypeBuilder;
665 TypeBuilder = builder.DefineNestedType (
668 (Type) null, //parent type
671 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
672 tc.RegisterOrder (this);
675 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
682 /// Performs semantic analysis, and then generates the IL interfaces
684 public override bool Define (TypeContainer parent)
686 if (!SemanticAnalysis ())
689 if (defined_method != null){
690 foreach (InterfaceMethod im in defined_method)
691 PopulateMethod (parent, this, im);
694 if (defined_properties != null){
695 foreach (InterfaceProperty ip in defined_properties)
696 PopulateProperty (parent, this, ip);
699 if (defined_events != null)
700 foreach (InterfaceEvent ie in defined_events)
701 PopulateEvent (parent, this, ie);
704 // FIXME: Pull the right indexer name out of the `IndexerName' attribute
706 if (defined_indexer != null) {
707 foreach (InterfaceIndexer ii in defined_indexer)
708 PopulateIndexer (parent, this, ii);
710 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
711 parent, "Item", ModFlags, Location);
713 TypeBuilder.SetCustomAttribute (cb);
719 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
724 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
726 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
727 ".ctor", MemberTypes.Constructor,
728 BindingFlags.Public | BindingFlags.Instance,
731 if (!(ml is MethodGroupExpr)) {
732 Console.WriteLine ("Internal error !!!!");
736 MethodGroupExpr mg = (MethodGroupExpr) ml;
738 MethodBase constructor = mg.Methods [0];
740 string [] vals = { name };
742 CustomAttributeBuilder cb = null;
744 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
746 Report.Warning (-100, "Can not set the indexer default member attribute");
754 public class InterfaceMemberBase {
755 public readonly string Name;
756 public readonly bool IsNew;
757 public Attributes OptAttributes;
759 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
763 OptAttributes = attrs;
767 public class InterfaceProperty : InterfaceMemberBase {
768 public readonly bool HasSet;
769 public readonly bool HasGet;
770 public readonly string Type;
771 public readonly string type;
772 public readonly Location Location;
774 public InterfaceProperty (string type, string name,
775 bool is_new, bool has_get, bool has_set,
776 Attributes attrs, Location loc)
777 : base (name, is_new, attrs)
786 public class InterfaceEvent : InterfaceMemberBase {
787 public readonly string Type;
789 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
790 : base (name, is_new, attrs)
796 public class InterfaceMethod : InterfaceMemberBase {
797 public readonly string ReturnType;
798 public readonly Parameters Parameters;
799 public readonly Location Location;
801 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args,
802 Attributes attrs, Location l)
803 : base (name, is_new, attrs)
805 this.ReturnType = return_type;
806 this.Parameters = args;
811 /// Returns the signature for this interface method
813 public string GetSignature (DeclSpace ds)
815 Type ret = RootContext.LookupType (ds, ReturnType, false, Location);
816 string args = Parameters.GetSignature (ds);
818 if ((ret == null) || (args == null))
821 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
824 public Type [] ParameterTypes (DeclSpace ds)
826 return Parameters.GetParameterInfo (ds);
830 public class InterfaceIndexer : InterfaceMemberBase {
831 public readonly bool HasGet, HasSet;
832 public readonly Parameters Parameters;
833 public readonly string Type;
834 public readonly Location Location;
836 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set,
837 bool is_new, Attributes attrs, Location loc)
838 : base ("", is_new, attrs)
847 public Type [] ParameterTypes (DeclSpace ds)
849 return Parameters.GetParameterInfo (ds);