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, IMemberContainer {
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 IMemberContainer parent_container;
54 MemberCache member_cache;
56 // These will happen after the semantic analysis
58 // Hashtable defined_indexers;
59 // Hashtable defined_methods;
62 /// Modifiers allowed in a class declaration
64 public const int AllowedModifiers =
72 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
73 : base (parent, name, l)
75 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
76 OptAttributes = attrs;
78 method_builders = new ArrayList ();
79 property_builders = new ArrayList ();
80 event_builders = new ArrayList ();
83 public AdditionResult AddMethod (InterfaceMethod imethod)
85 string name = imethod.Name;
86 Object value = defined_names [name];
89 if (!(value is InterfaceMethod))
90 return AdditionResult.NameExists;
93 if (defined_method == null)
94 defined_method = new ArrayList ();
96 defined_method.Add (imethod);
98 DefineName (name, imethod);
100 return AdditionResult.Success;
103 public AdditionResult AddProperty (InterfaceProperty iprop)
106 string name = iprop.Name;
108 if ((res = IsValid (name)) != AdditionResult.Success)
111 DefineName (name, iprop);
113 if (defined_properties == null)
114 defined_properties = new ArrayList ();
116 defined_properties.Add (iprop);
117 return AdditionResult.Success;
120 public AdditionResult AddEvent (InterfaceEvent ievent)
122 string name = ievent.Name;
125 if ((res = IsValid (name)) != AdditionResult.Success)
128 DefineName (name, ievent);
130 if (defined_events == null)
131 defined_events = new ArrayList ();
133 defined_events.Add (ievent);
134 return AdditionResult.Success;
137 public bool AddIndexer (InterfaceIndexer iindexer)
139 if (defined_indexer == null)
140 defined_indexer = new ArrayList ();
142 defined_indexer.Add (iindexer);
146 public ArrayList InterfaceMethods {
148 return defined_method;
152 public ArrayList InterfaceProperties {
154 return defined_properties;
158 public ArrayList InterfaceEvents {
160 return defined_events;
164 public ArrayList InterfaceIndexers {
166 return defined_indexer;
170 public ArrayList Bases {
180 public virtual TypeAttributes InterfaceAttr {
182 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
184 if (IsTopLevel == false) {
186 if ((ModFlags & Modifiers.PROTECTED) != 0
187 && (ModFlags & Modifiers.INTERNAL) != 0)
188 x |= TypeAttributes.NestedFamORAssem;
189 else if ((ModFlags & Modifiers.PROTECTED) != 0)
190 x |= TypeAttributes.NestedFamily;
191 else if ((ModFlags & Modifiers.INTERNAL) != 0)
192 x |= TypeAttributes.NestedAssembly;
193 else if ((ModFlags & Modifiers.PUBLIC) != 0)
194 x |= TypeAttributes.NestedPublic;
196 x |= TypeAttributes.NestedPrivate;
198 if ((ModFlags & Modifiers.PUBLIC) != 0)
199 x |= TypeAttributes.Public;
200 else if ((ModFlags & Modifiers.PRIVATE) != 0)
201 x |= TypeAttributes.NotPublic;
204 if ((ModFlags & Modifiers.ABSTRACT) != 0)
205 x |= TypeAttributes.Abstract;
207 if ((ModFlags & Modifiers.SEALED) != 0)
208 x |= TypeAttributes.Sealed;
214 void Error111 (InterfaceMemberBase ib)
218 "Interface `" + Name + "' already contains a definition with the " +
219 "same return value and parameter types for member `" + ib.Name + "'");
222 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
224 if (!TypeManager.RegisterMethod (mb, ip, types))
227 method_builders.Add (mb);
231 public MethodInfo [] GetMethods ()
233 int n = method_builders.Count;
234 MethodInfo [] mi = new MethodInfo [n];
236 method_builders.CopyTo (mi, 0);
241 // Hack around System.Reflection as found everywhere else
242 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
243 MemberFilter filter, object criteria)
245 ArrayList members = new ArrayList ();
247 if ((mt & MemberTypes.Method) != 0) {
248 foreach (MethodBuilder mb in method_builders)
249 if (filter (mb, criteria))
253 if ((mt & MemberTypes.Property) != 0) {
254 foreach (PropertyBuilder pb in property_builders)
255 if (filter (pb, criteria))
259 if ((mt & MemberTypes.Event) != 0) {
260 foreach (MyEventBuilder eb in event_builders)
261 if (filter (eb, criteria))
265 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
266 MemberList parent_mi;
268 parent_mi = TypeContainer.FindMembers (
269 TypeBuilder.BaseType, mt, bf, filter, criteria);
271 members.AddRange (parent_mi);
274 return new MemberList (members);
277 public override MemberCache MemberCache {
284 // Populates the methods in the interface
286 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
288 Type return_type = this.ResolveType (im.ReturnType, false, im.Location);
289 Type [] arg_types = im.ParameterTypes (this);
294 if (return_type == null)
297 if (return_type.IsPointer && !UnsafeOK (this))
300 if (arg_types == null)
303 foreach (Type t in arg_types){
308 if (t.IsPointer && !UnsafeOK (this))
315 mb = TypeBuilder.DefineMethod (
316 im.Name, interface_method_attributes,
317 return_type, arg_types);
319 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
321 if (!RegisterMethod (mb, ip, arg_types)) {
327 // Define each type attribute (in/out/ref) and
328 // the argument names.
330 p = im.Parameters.FixedParameters;
332 for (i = 0; i < p.Length; i++)
333 mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
335 if (i != arg_types.Length)
336 Console.WriteLine ("Implement the type definition for params");
339 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
340 return_type, ModFlags, false);
342 if (im.OptAttributes != null)
343 Attribute.ApplyAttributes (ec, mb, im, im.OptAttributes, Location);
347 // Populates the properties in the interface
349 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
352 MethodBuilder get = null, set = null;
353 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
354 Type prop_type = ip.Type.Type;
355 Type [] setter_args = new Type [1];
357 if (prop_type == null)
360 if (prop_type.IsPointer && !UnsafeOK (this))
363 setter_args [0] = prop_type;
366 // FIXME: properties are missing the following
367 // flags: hidebysig newslot specialname
369 pb = TypeBuilder.DefineProperty (
370 ip.Name, PropertyAttributes.None,
374 get = TypeBuilder.DefineMethod (
375 "get_" + ip.Name, property_attributes ,
379 // HACK because System.Reflection.Emit is lame
381 Type [] null_types = null;
382 InternalParameters inp = new InternalParameters
383 (null_types, Parameters.EmptyReadOnlyParameters);
385 if (!RegisterMethod (get, inp, null)) {
390 pb.SetGetMethod (get);
394 setter_args [0] = prop_type;
396 set = TypeBuilder.DefineMethod (
397 "set_" + ip.Name, property_attributes,
398 TypeManager.void_type, setter_args);
400 set.DefineParameter (1, ParameterAttributes.None, "value");
401 pb.SetSetMethod (set);
404 // HACK because System.Reflection.Emit is lame
406 Parameter [] parms = new Parameter [1];
407 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
408 InternalParameters ipp = new InternalParameters (
409 this, new Parameters (parms, null, Location.Null));
411 if (!RegisterMethod (set, ipp, setter_args)) {
417 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
418 null, ModFlags, false);
420 if (ip.OptAttributes != null)
421 Attribute.ApplyAttributes (ec, pb, ip, ip.OptAttributes, Location);
423 TypeManager.RegisterProperty (pb, get, set);
424 property_builders.Add (pb);
428 // Populates the events in the interface
430 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
433 // FIXME: We need to do this after delegates have been
434 // declared or we declare them recursively.
437 MethodBuilder add = null, remove = null;
438 ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
439 Type event_type = ie.Type.Type;
441 if (event_type == null)
444 if (event_type.IsPointer && !UnsafeOK (this))
447 Type [] parameters = new Type [1];
448 parameters [0] = event_type;
450 eb = new MyEventBuilder (TypeBuilder, ie.Name,
451 EventAttributes.None, event_type);
454 // Now define the accessors
456 string add_name = "add_" + ie.Name;
458 add = TypeBuilder.DefineMethod (
459 add_name, property_attributes, null, parameters);
460 add.DefineParameter (1, ParameterAttributes.None, "value");
461 eb.SetAddOnMethod (add);
463 string remove_name = "remove_" + ie.Name;
464 remove = TypeBuilder.DefineMethod (
465 remove_name, property_attributes, null, parameters);
466 remove.DefineParameter (1, ParameterAttributes.None, "value");
467 eb.SetRemoveOnMethod (remove);
469 Parameter [] parms = new Parameter [1];
470 parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
471 InternalParameters ip = new InternalParameters (
472 this, new Parameters (parms, null, Location.Null));
474 if (!RegisterMethod (add, ip, parameters)) {
479 if (!RegisterMethod (remove, ip, parameters)) {
484 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
485 null, ModFlags, false);
488 if (ie.OptAttributes != null)
489 Attribute.ApplyAttributes (ec, eb, ie, ie.OptAttributes, Location);
491 TypeManager.RegisterEvent (eb, add, remove);
492 event_builders.Add (eb);
496 // Populates the indexers in the interface
498 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
501 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
502 Type prop_type = ii.Type.Type;
503 Type [] arg_types = ii.ParameterTypes (this);
504 Type [] value_arg_types;
506 if (prop_type == null)
509 if (prop_type.IsPointer && !UnsafeOK (this))
513 // Sets up the extra invisible `value' argument for setters.
515 if (arg_types != null){
516 int count = arg_types.Length;
517 value_arg_types = new Type [count + 1];
519 arg_types.CopyTo (value_arg_types, 0);
520 value_arg_types [count] = prop_type;
522 foreach (Type t in arg_types){
523 if (t.IsPointer && !UnsafeOK (this))
527 value_arg_types = new Type [1];
529 value_arg_types [1] = prop_type;
532 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
533 null, ModFlags, false);
535 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
536 if (IndexerName == null)
537 IndexerName = "Item";
539 pb = TypeBuilder.DefineProperty (
540 IndexerName, PropertyAttributes.None,
541 prop_type, arg_types);
543 MethodBuilder set_item = null, get_item = null;
545 Parameter [] p = ii.Parameters.FixedParameters;
547 get_item = TypeBuilder.DefineMethod (
548 "get_" + IndexerName, property_attributes,
549 prop_type, arg_types);
550 pb.SetGetMethod (get_item);
552 // HACK because System.Reflection.Emit is lame
554 InternalParameters ip = new InternalParameters (
555 arg_types, ii.Parameters);
557 if (!RegisterMethod (get_item, ip, arg_types)) {
563 for (int i = 0; i < p.Length; i++)
564 get_item.DefineParameter (
566 p [i].Attributes, p [i].Name);
571 Parameter [] p = ii.Parameters.FixedParameters;
575 pv = new Parameter [p.Length + 1];
577 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
578 Parameters value_params = new Parameters (pv, null, Location.Null);
579 value_params.GetParameterInfo (decl_space);
581 set_item = TypeBuilder.DefineMethod (
582 "set_" + IndexerName, property_attributes,
583 TypeManager.void_type, value_arg_types);
584 pb.SetSetMethod (set_item);
586 // HACK because System.Reflection.Emit is lame
588 InternalParameters ip = new InternalParameters (
589 value_arg_types, value_params);
590 if (!RegisterMethod (set_item, ip, value_arg_types)) {
596 for (; i < p.Length; i++)
597 set_item.DefineParameter (
599 p [i].Attributes, p [i].Name);
602 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
605 if (ii.OptAttributes != null)
606 Attribute.ApplyAttributes (ec, pb, ii, ii.OptAttributes, Location);
608 property_builders.Add (pb);
612 /// Performs the semantic analysis for all the interface members
613 /// that were declared
615 bool SemanticAnalysis ()
617 Hashtable methods = new Hashtable ();
620 if (defined_method != null){
621 foreach (InterfaceMethod im in defined_method){
622 string sig = im.GetSignature (this);
625 // If there was an undefined Type on the signatures
630 if (methods [sig] != null){
638 // FIXME: Here I should check i
643 Type GetInterfaceTypeByName (string name)
645 Type t = FindType (name);
648 Report.Error (246, Location, "The type or namespace `" + name +
649 "' could not be found");
659 cause = "is a struct";
661 cause = "is a class";
663 cause = "Should not happen.";
665 Report.Error (527, Location, "`"+name+"' " + cause +
666 ", need an interface instead");
672 // Returns the list of interfaces that this interface implements
673 // Or null if it does not implement any interface.
675 // Sets the error boolean accoringly.
677 Type [] GetInterfaceBases (out bool error)
686 tbases = new Type [Bases.Count];
689 foreach (string name in Bases){
692 t = GetInterfaceTypeByName (name);
698 if (!Parent.AsAccessible (t, ModFlags))
699 Report.Error (61, Location,
700 "Inconsistent accessibility: base interface `" +
701 TypeManager.CSharpName (t) + "' is less " +
702 "accessible than interface `" +
708 return TypeManager.ExpandInterfaces (tbases);
713 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
717 // Rework the way we recurse, because for recursive
718 // definitions of interfaces (A:B and B:A) we report the
719 // error twice, rather than once.
721 public override TypeBuilder DefineType ()
726 if (TypeBuilder != null)
734 ifaces = GetInterfaceBases (out error);
740 ModuleBuilder builder = CodeGen.ModuleBuilder;
742 TypeBuilder = builder.DefineType (
745 (Type)null, // Parent Type
747 RootContext.RegisterOrder (this);
749 TypeBuilder builder = Parent.TypeBuilder;
751 TypeBuilder = builder.DefineNestedType (
754 (Type) null, //parent type
757 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
758 tc.RegisterOrder (this);
761 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
768 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
769 // interface is consistent. Either it is `Item' or it is the name defined by all the
770 // indexers with the `IndexerName' attribute.
772 // Turns out that the IndexerNameAttribute is applied to each indexer,
773 // but it is never emitted, instead a DefaultName attribute is attached
776 void DefineIndexers (TypeContainer parent)
778 string interface_indexer_name = null;
780 foreach (InterfaceIndexer ii in defined_indexer){
782 PopulateIndexer (parent, this, ii);
784 if (interface_indexer_name == null){
785 interface_indexer_name = IndexerName;
789 if (IndexerName == interface_indexer_name)
793 668, "Two indexers have different names, " +
794 " you should use the same name for all your indexers");
796 if (interface_indexer_name == null)
797 interface_indexer_name = "Item";
798 IndexerName = interface_indexer_name;
802 /// Performs semantic analysis, and then generates the IL interfaces
804 public override bool DefineMembers (TypeContainer parent)
806 if (!SemanticAnalysis ())
809 if (defined_method != null){
810 foreach (InterfaceMethod im in defined_method)
811 PopulateMethod (parent, this, im);
814 if (defined_properties != null){
815 foreach (InterfaceProperty ip in defined_properties)
816 PopulateProperty (parent, this, ip);
819 if (defined_events != null)
820 foreach (InterfaceEvent ie in defined_events)
821 PopulateEvent (parent, this, ie);
823 if (defined_indexer != null) {
824 DefineIndexers (parent);
826 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
827 parent, IndexerName, ModFlags, Location);
829 TypeBuilder.SetCustomAttribute (cb);
833 if (TypeBuilder.BaseType != null)
834 parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
836 member_cache = new MemberCache (this);
843 /// Applies all the attributes.
845 public override bool Define (TypeContainer parent)
847 if (OptAttributes != null) {
848 EmitContext ec = new EmitContext (parent, this, Location, null, null,
850 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
856 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
861 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
863 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
864 ".ctor", MemberTypes.Constructor,
865 BindingFlags.Public | BindingFlags.Instance,
868 if (!(ml is MethodGroupExpr)) {
869 Console.WriteLine ("Internal error !!!!");
873 MethodGroupExpr mg = (MethodGroupExpr) ml;
875 MethodBase constructor = mg.Methods [0];
877 string [] vals = { name };
879 CustomAttributeBuilder cb = null;
881 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
883 Report.Warning (-100, "Can not set the indexer default member attribute");
893 string IMemberContainer.Name {
899 Type IMemberContainer.Type {
905 IMemberContainer IMemberContainer.Parent {
907 return parent_container;
911 MemberCache IMemberContainer.MemberCache {
917 bool IMemberContainer.IsInterface {
923 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
925 // Interfaces only contain instance members.
926 if ((bf & BindingFlags.Instance) == 0)
927 return MemberList.Empty;
928 if ((bf & BindingFlags.Public) == 0)
929 return MemberList.Empty;
931 ArrayList members = new ArrayList ();
933 if ((mt & MemberTypes.Method) != 0)
934 members.AddRange (method_builders);
936 if ((mt & MemberTypes.Property) != 0)
937 members.AddRange (property_builders);
939 if ((mt & MemberTypes.Event) != 0)
940 members.AddRange (event_builders);
942 return new MemberList (members);
946 public class InterfaceMemberBase {
947 public readonly string Name;
948 public readonly bool IsNew;
949 public Attributes OptAttributes;
951 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
955 OptAttributes = attrs;
959 public class InterfaceProperty : InterfaceMemberBase {
960 public readonly bool HasSet;
961 public readonly bool HasGet;
962 public readonly Location Location;
963 public Expression Type;
965 public InterfaceProperty (Expression type, string name,
966 bool is_new, bool has_get, bool has_set,
967 Attributes attrs, Location loc)
968 : base (name, is_new, attrs)
977 public class InterfaceEvent : InterfaceMemberBase {
978 public readonly Location Location;
979 public Expression Type;
981 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
983 : base (name, is_new, attrs)
990 public class InterfaceMethod : InterfaceMemberBase {
991 public readonly Expression ReturnType;
992 public readonly Parameters Parameters;
993 public readonly Location Location;
995 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
996 Attributes attrs, Location l)
997 : base (name, is_new, attrs)
999 this.ReturnType = return_type;
1000 this.Parameters = args;
1005 /// Returns the signature for this interface method
1007 public string GetSignature (DeclSpace ds)
1009 Type ret = ds.ResolveType (ReturnType, false, Location);
1010 string args = Parameters.GetSignature (ds);
1012 if ((ret == null) || (args == null))
1015 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
1018 public Type [] ParameterTypes (DeclSpace ds)
1020 return Parameters.GetParameterInfo (ds);
1024 public class InterfaceIndexer : InterfaceMemberBase {
1025 public readonly bool HasGet, HasSet;
1026 public readonly Parameters Parameters;
1027 public readonly Location Location;
1028 public Expression Type;
1030 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
1031 bool is_new, Attributes attrs, Location loc)
1032 : base ("", is_new, attrs)
1041 public Type [] ParameterTypes (DeclSpace ds)
1043 return Parameters.GetParameterInfo (ds);