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 public string IndexerName;
52 // These will happen after the semantic analysis
54 // Hashtable defined_indexers;
55 // Hashtable defined_methods;
58 /// Modifiers allowed in a class declaration
60 public const int AllowedModifiers =
68 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
69 : base (parent, name, l)
71 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
72 OptAttributes = attrs;
74 method_builders = new ArrayList ();
75 property_builders = new ArrayList ();
78 public AdditionResult AddMethod (InterfaceMethod imethod)
80 string name = imethod.Name;
81 Object value = defined_names [name];
84 if (!(value is InterfaceMethod))
85 return AdditionResult.NameExists;
88 if (defined_method == null)
89 defined_method = new ArrayList ();
91 defined_method.Add (imethod);
93 DefineName (name, imethod);
95 return AdditionResult.Success;
98 public AdditionResult AddProperty (InterfaceProperty iprop)
101 string name = iprop.Name;
103 if ((res = IsValid (name)) != AdditionResult.Success)
106 DefineName (name, iprop);
108 if (defined_properties == null)
109 defined_properties = new ArrayList ();
111 defined_properties.Add (iprop);
112 return AdditionResult.Success;
115 public AdditionResult AddEvent (InterfaceEvent ievent)
117 string name = ievent.Name;
120 if ((res = IsValid (name)) != AdditionResult.Success)
123 DefineName (name, ievent);
125 if (defined_events == null)
126 defined_events = new ArrayList ();
128 defined_events.Add (ievent);
129 return AdditionResult.Success;
132 public bool AddIndexer (InterfaceIndexer iindexer)
134 if (defined_indexer == null)
135 defined_indexer = new ArrayList ();
137 defined_indexer.Add (iindexer);
141 public ArrayList InterfaceMethods {
143 return defined_method;
147 public ArrayList InterfaceProperties {
149 return defined_properties;
153 public ArrayList InterfaceEvents {
155 return defined_events;
159 public ArrayList InterfaceIndexers {
161 return defined_indexer;
165 public ArrayList Bases {
175 public virtual TypeAttributes InterfaceAttr {
177 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
179 if (IsTopLevel == false) {
181 if ((ModFlags & Modifiers.PROTECTED) != 0
182 && (ModFlags & Modifiers.INTERNAL) != 0)
183 x |= TypeAttributes.NestedFamORAssem;
184 else if ((ModFlags & Modifiers.PROTECTED) != 0)
185 x |= TypeAttributes.NestedFamily;
186 else if ((ModFlags & Modifiers.INTERNAL) != 0)
187 x |= TypeAttributes.NestedAssembly;
188 else if ((ModFlags & Modifiers.PUBLIC) != 0)
189 x |= TypeAttributes.NestedPublic;
191 x |= TypeAttributes.NestedPrivate;
193 if ((ModFlags & Modifiers.PUBLIC) != 0)
194 x |= TypeAttributes.Public;
195 else if ((ModFlags & Modifiers.PRIVATE) != 0)
196 x |= TypeAttributes.NotPublic;
199 if ((ModFlags & Modifiers.ABSTRACT) != 0)
200 x |= TypeAttributes.Abstract;
202 if ((ModFlags & Modifiers.SEALED) != 0)
203 x |= TypeAttributes.Sealed;
209 void Error111 (InterfaceMemberBase ib)
213 "Interface `" + Name + "' already contains a definition with the " +
214 "same return value and parameter types for member `" + ib.Name + "'");
217 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
219 if (!TypeManager.RegisterMethod (mb, ip, types))
222 method_builders.Add (mb);
226 public MethodInfo [] GetMethods ()
228 int n = method_builders.Count;
229 MethodInfo [] mi = new MethodInfo [n];
231 method_builders.CopyTo (mi, 0);
236 // Hack around System.Reflection as found everywhere else
237 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
239 ArrayList members = new ArrayList ();
241 if ((mt & MemberTypes.Method) != 0) {
242 foreach (MethodBuilder mb in method_builders)
243 if (filter (mb, criteria))
247 if ((mt & MemberTypes.Property) != 0) {
248 foreach (PropertyBuilder pb in property_builders)
249 if (filter (pb, criteria))
253 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
254 MemberInfo [] parent_mi;
256 parent_mi = TypeContainer.FindMembers (
257 TypeBuilder.BaseType, mt, bf, filter, criteria);
259 if (parent_mi != null)
260 members.AddRange (parent_mi);
263 // The rest of the cases, if any, are unhandled at present.
265 int count = members.Count;
268 MemberInfo [] mi = new MemberInfo [count];
269 members.CopyTo (mi, 0);
277 // Populates the methods in the interface
279 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
281 Type return_type = this.ResolveType (im.ReturnType, false, im.Location);
282 Type [] arg_types = im.ParameterTypes (this);
287 if (return_type == null)
290 if (return_type.IsPointer && !UnsafeOK (this))
293 foreach (Type t in arg_types){
298 if (t.IsPointer && !UnsafeOK (this))
305 mb = TypeBuilder.DefineMethod (
306 im.Name, interface_method_attributes,
307 return_type, arg_types);
309 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
311 if (!RegisterMethod (mb, ip, arg_types)) {
317 // Define each type attribute (in/out/ref) and
318 // the argument names.
320 p = im.Parameters.FixedParameters;
322 for (i = 0; i < p.Length; i++)
323 mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
325 if (i != arg_types.Length)
326 Console.WriteLine ("Implement the type definition for params");
329 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
330 return_type, ModFlags, false);
332 if (im.OptAttributes != null)
333 Attribute.ApplyAttributes (ec, mb, im, im.OptAttributes, Location);
337 // Populates the properties in the interface
339 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
342 MethodBuilder get = null, set = null;
343 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
344 Type prop_type = ip.Type.Type;
345 Type [] setter_args = new Type [1];
347 if (prop_type == null)
350 if (prop_type.IsPointer && !UnsafeOK (this))
353 setter_args [0] = prop_type;
356 // FIXME: properties are missing the following
357 // flags: hidebysig newslot specialname
359 pb = TypeBuilder.DefineProperty (
360 ip.Name, PropertyAttributes.None,
364 get = TypeBuilder.DefineMethod (
365 "get_" + ip.Name, property_attributes ,
369 // HACK because System.Reflection.Emit is lame
371 Type [] null_types = null;
372 InternalParameters inp = new InternalParameters
373 (null_types, Parameters.GetEmptyReadOnlyParameters ());
375 if (!RegisterMethod (get, inp, null)) {
380 pb.SetGetMethod (get);
384 setter_args [0] = prop_type;
386 set = TypeBuilder.DefineMethod (
387 "set_" + ip.Name, property_attributes,
388 TypeManager.void_type, setter_args);
390 set.DefineParameter (1, ParameterAttributes.None, "value");
391 pb.SetSetMethod (set);
394 // HACK because System.Reflection.Emit is lame
396 Parameter [] parms = new Parameter [1];
397 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
398 InternalParameters ipp = new InternalParameters (
399 this, new Parameters (parms, null, Location.Null));
401 if (!RegisterMethod (set, ipp, setter_args)) {
407 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
408 null, ModFlags, false);
410 if (ip.OptAttributes != null)
411 Attribute.ApplyAttributes (ec, pb, ip, ip.OptAttributes, Location);
413 TypeManager.RegisterProperty (pb, get, set);
414 property_builders.Add (pb);
418 // Populates the events in the interface
420 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
423 // FIXME: We need to do this after delegates have been
424 // declared or we declare them recursively.
429 // Populates the indexers in the interface
431 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
434 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
435 Type prop_type = ii.Type.Type;
436 Type [] arg_types = ii.ParameterTypes (this);
437 Type [] value_arg_types;
439 if (prop_type == null)
442 if (prop_type.IsPointer && !UnsafeOK (this))
446 // Sets up the extra invisible `value' argument for setters.
448 if (arg_types != null){
449 int count = arg_types.Length;
450 value_arg_types = new Type [count + 1];
452 arg_types.CopyTo (value_arg_types, 0);
453 value_arg_types [count] = prop_type;
455 foreach (Type t in arg_types){
456 if (t.IsPointer && !UnsafeOK (this))
460 value_arg_types = new Type [1];
462 value_arg_types [1] = prop_type;
465 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
466 null, ModFlags, false);
468 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
469 if (IndexerName == null)
470 IndexerName = "Item";
472 pb = TypeBuilder.DefineProperty (
473 IndexerName, PropertyAttributes.None,
474 prop_type, arg_types);
476 MethodBuilder set_item = null, get_item = null;
478 Parameter [] p = ii.Parameters.FixedParameters;
480 get_item = TypeBuilder.DefineMethod (
481 "get_" + IndexerName, property_attributes,
482 prop_type, arg_types);
483 pb.SetGetMethod (get_item);
485 // HACK because System.Reflection.Emit is lame
487 InternalParameters ip = new InternalParameters (
488 arg_types, ii.Parameters);
490 if (!RegisterMethod (get_item, ip, arg_types)) {
496 for (int i = 0; i < p.Length; i++)
497 get_item.DefineParameter (
499 p [i].Attributes, p [i].Name);
504 Parameter [] p = ii.Parameters.FixedParameters;
508 pv = new Parameter [p.Length + 1];
510 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
511 Parameters value_params = new Parameters (pv, null, Location.Null);
512 value_params.GetParameterInfo (decl_space);
514 set_item = TypeBuilder.DefineMethod (
515 "set_" + IndexerName, property_attributes,
516 TypeManager.void_type, value_arg_types);
517 pb.SetSetMethod (set_item);
519 // HACK because System.Reflection.Emit is lame
521 InternalParameters ip = new InternalParameters (
522 value_arg_types, value_params);
523 if (!RegisterMethod (set_item, ip, value_arg_types)) {
529 for (; i < p.Length; i++)
530 set_item.DefineParameter (
532 p [i].Attributes, p [i].Name);
535 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
538 if (ii.OptAttributes != null)
539 Attribute.ApplyAttributes (ec, pb, ii, ii.OptAttributes, Location);
541 property_builders.Add (pb);
545 /// Performs the semantic analysis for all the interface members
546 /// that were declared
548 bool SemanticAnalysis ()
550 Hashtable methods = new Hashtable ();
553 if (defined_method != null){
554 foreach (InterfaceMethod im in defined_method){
555 string sig = im.GetSignature (this);
558 // If there was an undefined Type on the signatures
563 if (methods [sig] != null){
571 // FIXME: Here I should check i
576 Type GetInterfaceTypeByName (string name)
578 Type t = FindType (name);
589 cause = "is a struct";
591 cause = "is a class";
593 cause = "Should not happen.";
595 Report.Error (527, Location, "`"+name+"' " + cause +
596 ", need an interface instead");
602 // Returns the list of interfaces that this interface implements
603 // Or null if it does not implement any interface.
605 // Sets the error boolean accoringly.
607 Type [] GetInterfaceBases (out bool error)
616 tbases = new Type [Bases.Count];
619 foreach (string name in Bases){
622 t = GetInterfaceTypeByName (name);
631 return TypeManager.ExpandInterfaces (tbases);
636 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
640 // Rework the way we recurse, because for recursive
641 // definitions of interfaces (A:B and B:A) we report the
642 // error twice, rather than once.
644 public override TypeBuilder DefineType ()
649 if (TypeBuilder != null)
657 ifaces = GetInterfaceBases (out error);
663 ModuleBuilder builder = CodeGen.ModuleBuilder;
665 TypeBuilder = builder.DefineType (
668 (Type)null, // Parent Type
670 RootContext.RegisterOrder (this);
672 TypeBuilder builder = Parent.TypeBuilder;
674 TypeBuilder = builder.DefineNestedType (
677 (Type) null, //parent type
680 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
681 tc.RegisterOrder (this);
684 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
691 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
692 // interface is consistent. Either it is `Item' or it is the name defined by all the
693 // indexers with the `IndexerName' attribute.
695 // Turns out that the IndexerNameAttribute is applied to each indexer,
696 // but it is never emitted, instead a DefaultName attribute is attached
699 void DefineIndexers (TypeContainer parent)
701 string interface_indexer_name;
703 foreach (InterfaceIndexer ii in defined_indexer){
705 PopulateIndexer (parent, this, ii);
707 if (interface_indexer_name == null){
708 interface_indexer_name = IndexerName;
712 if (IndexerName == interface_indexer_name)
716 668, "Two indexers have different names, " +
717 " you should use the same name for all your indexers");
719 if (interface_indexer_name == null)
720 interface_indexer_name = "Item";
721 IndexerName = interface_indexer_name;
725 /// Performs semantic analysis, and then generates the IL interfaces
727 public override bool Define (TypeContainer parent)
729 if (!SemanticAnalysis ())
732 if (defined_method != null){
733 foreach (InterfaceMethod im in defined_method)
734 PopulateMethod (parent, this, im);
737 if (defined_properties != null){
738 foreach (InterfaceProperty ip in defined_properties)
739 PopulateProperty (parent, this, ip);
742 if (defined_events != null)
743 foreach (InterfaceEvent ie in defined_events)
744 PopulateEvent (parent, this, ie);
746 if (defined_indexer != null) {
747 DefineIndexers (parent);
749 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
750 parent, IndexerName, ModFlags, Location);
752 TypeBuilder.SetCustomAttribute (cb);
758 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
763 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
765 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
766 ".ctor", MemberTypes.Constructor,
767 BindingFlags.Public | BindingFlags.Instance,
770 if (!(ml is MethodGroupExpr)) {
771 Console.WriteLine ("Internal error !!!!");
775 MethodGroupExpr mg = (MethodGroupExpr) ml;
777 MethodBase constructor = mg.Methods [0];
779 string [] vals = { name };
781 CustomAttributeBuilder cb = null;
783 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
785 Report.Warning (-100, "Can not set the indexer default member attribute");
793 public class InterfaceMemberBase {
794 public readonly string Name;
795 public readonly bool IsNew;
796 public Attributes OptAttributes;
798 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
802 OptAttributes = attrs;
806 public class InterfaceProperty : InterfaceMemberBase {
807 public readonly bool HasSet;
808 public readonly bool HasGet;
809 public readonly Location Location;
810 public Expression Type;
812 public InterfaceProperty (Expression type, string name,
813 bool is_new, bool has_get, bool has_set,
814 Attributes attrs, Location loc)
815 : base (name, is_new, attrs)
824 public class InterfaceEvent : InterfaceMemberBase {
825 public readonly Expression Type;
827 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs)
828 : base (name, is_new, attrs)
834 public class InterfaceMethod : InterfaceMemberBase {
835 public readonly Expression ReturnType;
836 public readonly Parameters Parameters;
837 public readonly Location Location;
839 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
840 Attributes attrs, Location l)
841 : base (name, is_new, attrs)
843 this.ReturnType = return_type;
844 this.Parameters = args;
849 /// Returns the signature for this interface method
851 public string GetSignature (DeclSpace ds)
853 Type ret = ds.ResolveType (ReturnType, false, Location);
854 string args = Parameters.GetSignature (ds);
856 if ((ret == null) || (args == null))
859 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
862 public Type [] ParameterTypes (DeclSpace ds)
864 return Parameters.GetParameterInfo (ds);
868 public class InterfaceIndexer : InterfaceMemberBase {
869 public readonly bool HasGet, HasSet;
870 public readonly Parameters Parameters;
871 public readonly Location Location;
872 public Expression Type;
874 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
875 bool is_new, Attributes attrs, Location loc)
876 : base ("", is_new, attrs)
885 public Type [] ParameterTypes (DeclSpace ds)
887 return Parameters.GetParameterInfo (ds);