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 bool IsTopLevel {
176 if (Parent.Parent == null)
183 public virtual TypeAttributes InterfaceAttr {
185 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
187 if (IsTopLevel == false) {
189 if ((ModFlags & Modifiers.PROTECTED) != 0
190 && (ModFlags & Modifiers.INTERNAL) != 0)
191 x |= TypeAttributes.NestedFamORAssem;
192 else if ((ModFlags & Modifiers.PROTECTED) != 0)
193 x |= TypeAttributes.NestedFamily;
194 else if ((ModFlags & Modifiers.INTERNAL) != 0)
195 x |= TypeAttributes.NestedAssembly;
196 else if ((ModFlags & Modifiers.PUBLIC) != 0)
197 x |= TypeAttributes.NestedPublic;
199 x |= TypeAttributes.NestedPrivate;
201 if ((ModFlags & Modifiers.PUBLIC) != 0)
202 x |= TypeAttributes.Public;
203 else if ((ModFlags & Modifiers.PRIVATE) != 0)
204 x |= TypeAttributes.NotPublic;
207 if ((ModFlags & Modifiers.ABSTRACT) != 0)
208 x |= TypeAttributes.Abstract;
210 if ((ModFlags & Modifiers.SEALED) != 0)
211 x |= TypeAttributes.Sealed;
217 void Error111 (InterfaceMemberBase ib)
221 "Interface `" + Name + "' already contains a definition with the " +
222 "same return value and parameter types for member `" + ib.Name + "'");
225 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
227 if (!TypeManager.RegisterMethod (mb, ip, types))
230 method_builders.Add (mb);
234 public MethodInfo [] GetMethods ()
236 int n = method_builders.Count;
237 MethodInfo [] mi = new MethodInfo [n];
239 method_builders.CopyTo (mi, 0);
244 // Hack around System.Reflection as found everywhere else
245 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
247 ArrayList members = new ArrayList ();
249 if ((mt & MemberTypes.Method) != 0) {
250 foreach (MethodBuilder mb in method_builders)
251 if (filter (mb, criteria))
255 if ((mt & MemberTypes.Property) != 0) {
256 foreach (PropertyBuilder pb in property_builders)
257 if (filter (pb, criteria))
261 if ((bf & BindingFlags.DeclaredOnly) == 0){
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 (InterfaceMethod im)
289 Type return_type = RootContext.LookupType (this, 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");
339 // Populates the properties in the interface
341 void PopulateProperty (InterfaceProperty ip)
344 MethodBuilder get = null, set = null;
345 Type prop_type = RootContext.LookupType (this, ip.Type, false, ip.Location);
346 Type [] setter_args = new Type [1];
348 if (prop_type == null)
351 if (prop_type.IsPointer && !UnsafeOK (this))
354 setter_args [0] = prop_type;
357 // FIXME: properties are missing the following
358 // flags: hidebysig newslot specialname
360 pb = TypeBuilder.DefineProperty (
361 ip.Name, PropertyAttributes.None,
365 get = TypeBuilder.DefineMethod (
366 "get_" + ip.Name, property_attributes ,
370 // HACK because System.Reflection.Emit is lame
372 Type [] null_types = null;
373 InternalParameters inp = new InternalParameters
374 (null_types, Parameters.GetEmptyReadOnlyParameters ());
376 if (!RegisterMethod (get, inp, null)) {
381 pb.SetGetMethod (get);
385 setter_args [0] = prop_type;
387 set = TypeBuilder.DefineMethod (
388 "set_" + ip.Name, property_attributes,
389 TypeManager.void_type, setter_args);
391 set.DefineParameter (1, ParameterAttributes.None, "value");
392 pb.SetSetMethod (set);
395 // HACK because System.Reflection.Emit is lame
397 Parameter [] parms = new Parameter [1];
398 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
399 InternalParameters ipp = new InternalParameters (
400 this, new Parameters (parms, null, Location.Null));
402 if (!RegisterMethod (set, ipp, setter_args)) {
408 TypeManager.RegisterProperty (pb, get, set);
409 property_builders.Add (pb);
413 // Populates the events in the interface
415 void PopulateEvent (InterfaceEvent ie)
418 // FIXME: We need to do this after delegates have been
419 // declared or we declare them recursively.
424 // Populates the indexers in the interface
426 void PopulateIndexer (InterfaceIndexer ii)
429 Type prop_type = RootContext.LookupType (this, ii.Type, false, ii.Location);
430 Type [] arg_types = ii.ParameterTypes (this);
431 Type [] value_arg_types;
433 if (prop_type == null)
436 if (prop_type.IsPointer && !UnsafeOK (this))
440 // Sets up the extra invisible `value' argument for setters.
442 if (arg_types != null){
443 int count = arg_types.Length;
444 value_arg_types = new Type [count + 1];
446 arg_types.CopyTo (value_arg_types, 0);
447 value_arg_types [count] = prop_type;
449 foreach (Type t in arg_types){
450 if (t.IsPointer && !UnsafeOK (this))
454 value_arg_types = new Type [1];
456 value_arg_types [1] = prop_type;
459 pb = TypeBuilder.DefineProperty (
460 "Item", PropertyAttributes.None,
461 prop_type, arg_types);
464 MethodBuilder get_item;
465 Parameter [] p = ii.Parameters.FixedParameters;
467 get_item = TypeBuilder.DefineMethod (
468 "get_Item", property_attributes, prop_type, arg_types);
469 pb.SetGetMethod (get_item);
471 // HACK because System.Reflection.Emit is lame
473 InternalParameters ip = new InternalParameters (
474 arg_types, ii.Parameters);
476 if (!RegisterMethod (get_item, ip, arg_types)) {
482 for (int i = 0; i < p.Length; i++)
483 get_item.DefineParameter (
485 p [i].Attributes, p [i].Name);
490 Parameter [] p = ii.Parameters.FixedParameters;
491 MethodBuilder set_item;
494 set_item = TypeBuilder.DefineMethod (
495 "set_Item", property_attributes,
496 TypeManager.void_type, value_arg_types);
497 pb.SetSetMethod (set_item);
499 // HACK because System.Reflection.Emit is lame
501 InternalParameters ip = new InternalParameters (
502 value_arg_types, ii.Parameters);
503 if (!RegisterMethod (set_item, ip, value_arg_types)) {
509 for (; i < p.Length; i++)
510 set_item.DefineParameter (
512 p [i].Attributes, p [i].Name);
515 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
520 /// Performs the semantic analysis for all the interface members
521 /// that were declared
523 bool SemanticAnalysis ()
525 Hashtable methods = new Hashtable ();
528 if (defined_method != null){
529 foreach (InterfaceMethod im in defined_method){
530 string sig = im.GetSignature (this);
533 // If there was an undefined Type on the signatures
538 if (methods [sig] != null){
546 // FIXME: Here I should check i
552 // Returns the Type that represents the interface whose name
556 Type LookupInterfaceByName (object builder, string ns, string name, out bool error)
562 name = TypeContainer.MakeFQN (ns, name);
563 t = TypeManager.LookupType (name);
572 cause = "is a struct";
574 cause = "is a class";
576 cause = "Should not happen.";
579 Report.Error (527, Location, "`"+name+"' " + cause +
580 ", need an interface instead");
585 Tree tree = RootContext.Tree;
586 parent = (Interface) tree.Interfaces [name];
590 t = parent.DefineInterface (builder);
593 "Inherited interface `"+name+"' is circular");
601 Type GetInterfaceTypeByName (object builder, string name)
604 // For the case the type we are looking for is nested within this one
605 // or is in any base class
607 DeclSpace containing_ds = this;
611 while (containing_ds != null){
612 Type current_type = containing_ds.TypeBuilder;
614 while (current_type != null) {
615 string pre = current_type.FullName;
617 t = LookupInterfaceByName (builder, pre, name, out error);
624 current_type = current_type.BaseType;
626 containing_ds = containing_ds.Parent;
630 // Attempt to lookup the class on our namespace and all it's implicit parents
632 for (string ns = Namespace.Name; ns != null; ns = RootContext.ImplicitParent (ns)){
633 t = LookupInterfaceByName (builder, ns, name, out error);
641 // Attempt to do a direct unqualified lookup
643 t = LookupInterfaceByName (builder, "", name, out error);
651 // Attempt to lookup the class on any of the `using'
655 for (Namespace ns = Namespace; ns != null; ns = ns.Parent){
656 t = LookupInterfaceByName (builder, ns.Name, name, out error);
664 // Now check the using clause list
666 ArrayList using_list = ns.UsingTable;
668 if (using_list == null)
671 foreach (string n in using_list){
672 t = LookupInterfaceByName (builder, n, name, out error);
681 Report.Error (246, Location, "Can not find type `"+name+"'");
686 // Returns the list of interfaces that this interface implements
687 // Or null if it does not implement any interface.
689 // Sets the error boolean accoringly.
691 Type [] GetInterfaceBases (object builder, out bool error)
700 tbases = new Type [Bases.Count];
703 foreach (string name in Bases){
706 t = GetInterfaceTypeByName (builder, name);
720 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
723 // Rework the way we recurse, because for recursive
724 // definitions of interfaces (A:B and B:A) we report the
725 // error twice, rather than once.
727 public TypeBuilder DefineInterface (object parent_builder)
732 if (TypeBuilder != null)
740 ifaces = GetInterfaceBases (parent_builder, out error);
745 if (parent_builder is ModuleBuilder) {
746 ModuleBuilder builder = (ModuleBuilder) parent_builder;
748 TypeBuilder = builder.DefineType (
751 (Type)null, // Parent Type
753 RootContext.RegisterOrder (this);
755 TypeBuilder builder = (System.Reflection.Emit.TypeBuilder) parent_builder;
757 TypeBuilder = builder.DefineNestedType (
760 (Type) null, //parent type
763 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
764 tc.RegisterOrder (this);
767 TypeManager.AddUserInterface (Name, TypeBuilder, this);
774 /// Performs semantic analysis, and then generates the IL interfaces
776 public override bool Define (TypeContainer parent)
778 if (!SemanticAnalysis ())
781 if (defined_method != null){
782 foreach (InterfaceMethod im in defined_method)
786 if (defined_properties != null){
787 foreach (InterfaceProperty ip in defined_properties)
788 PopulateProperty (ip);
791 if (defined_events != null)
792 foreach (InterfaceEvent ie in defined_events)
795 if (defined_indexer != null) {
796 foreach (InterfaceIndexer ii in defined_indexer)
797 PopulateIndexer (ii);
799 CustomAttributeBuilder cb = EmitDefaultMemberAttr (parent, ModFlags, Location);
800 TypeBuilder.SetCustomAttribute (cb);
806 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent, int flags,
809 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
811 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
812 ".ctor", MemberTypes.Constructor,
813 BindingFlags.Public | BindingFlags.Instance,
816 if (!(ml is MethodGroupExpr)) {
817 Console.WriteLine ("Internal error !!!!");
821 MethodGroupExpr mg = (MethodGroupExpr) ml;
823 MethodBase constructor = mg.Methods [0];
825 string [] vals = { "Item" };
827 CustomAttributeBuilder cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
834 public class InterfaceMemberBase {
835 public readonly string Name;
836 public readonly bool IsNew;
837 public Attributes OptAttributes;
839 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
843 OptAttributes = attrs;
847 public class InterfaceProperty : InterfaceMemberBase {
848 public readonly bool HasSet;
849 public readonly bool HasGet;
850 public readonly string Type;
851 public readonly string type;
852 public readonly Location Location;
854 public InterfaceProperty (string type, string name,
855 bool is_new, bool has_get, bool has_set,
856 Attributes attrs, Location loc)
857 : base (name, is_new, attrs)
866 public class InterfaceEvent : InterfaceMemberBase {
867 public readonly string Type;
869 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
870 : base (name, is_new, attrs)
876 public class InterfaceMethod : InterfaceMemberBase {
877 public readonly string ReturnType;
878 public readonly Parameters Parameters;
879 public readonly Location Location;
881 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args,
882 Attributes attrs, Location l)
883 : base (name, is_new, attrs)
885 this.ReturnType = return_type;
886 this.Parameters = args;
891 /// Returns the signature for this interface method
893 public string GetSignature (DeclSpace ds)
895 Type ret = RootContext.LookupType (ds, ReturnType, false, Location);
896 string args = Parameters.GetSignature (ds);
898 if ((ret == null) || (args == null))
901 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
904 public Type [] ParameterTypes (DeclSpace ds)
906 return Parameters.GetParameterInfo (ds);
910 public class InterfaceIndexer : InterfaceMemberBase {
911 public readonly bool HasGet, HasSet;
912 public readonly Parameters Parameters;
913 public readonly string Type;
914 public readonly Location Location;
916 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set,
917 bool is_new, Attributes attrs, Location loc)
918 : base ("", is_new, attrs)
927 public Type [] ParameterTypes (DeclSpace ds)
929 return Parameters.GetParameterInfo (ds);