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;
58 // These will happen after the semantic analysis
60 // Hashtable defined_indexers;
61 // Hashtable defined_methods;
64 /// Modifiers allowed in a class declaration
66 public const int AllowedModifiers =
74 public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
75 : base (parent, name, l)
77 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
78 OptAttributes = attrs;
80 method_builders = new ArrayList ();
81 property_builders = new ArrayList ();
82 event_builders = new ArrayList ();
85 public AdditionResult AddMethod (InterfaceMethod imethod)
87 string name = imethod.Name;
88 Object value = defined_names [name];
91 if (!(value is InterfaceMethod))
92 return AdditionResult.NameExists;
95 if (defined_method == null)
96 defined_method = new ArrayList ();
98 defined_method.Add (imethod);
100 DefineName (name, imethod);
102 return AdditionResult.Success;
105 public AdditionResult AddProperty (InterfaceProperty iprop)
108 string name = iprop.Name;
110 if ((res = IsValid (name, name)) != AdditionResult.Success)
113 DefineName (name, iprop);
115 if (defined_properties == null)
116 defined_properties = new ArrayList ();
118 defined_properties.Add (iprop);
119 return AdditionResult.Success;
122 public AdditionResult AddEvent (InterfaceEvent ievent)
124 string name = ievent.Name;
127 if ((res = IsValid (name, name)) != AdditionResult.Success)
130 DefineName (name, ievent);
132 if (defined_events == null)
133 defined_events = new ArrayList ();
135 defined_events.Add (ievent);
136 return AdditionResult.Success;
139 public bool AddIndexer (InterfaceIndexer iindexer)
141 if (defined_indexer == null)
142 defined_indexer = new ArrayList ();
144 defined_indexer.Add (iindexer);
148 public ArrayList InterfaceMethods {
150 return defined_method;
154 public ArrayList InterfaceProperties {
156 return defined_properties;
160 public ArrayList InterfaceEvents {
162 return defined_events;
166 public ArrayList InterfaceIndexers {
168 return defined_indexer;
172 public ArrayList Bases {
182 public virtual TypeAttributes InterfaceAttr {
184 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
186 if (IsTopLevel == false) {
188 if ((ModFlags & Modifiers.PROTECTED) != 0
189 && (ModFlags & Modifiers.INTERNAL) != 0)
190 x |= TypeAttributes.NestedFamORAssem;
191 else if ((ModFlags & Modifiers.PROTECTED) != 0)
192 x |= TypeAttributes.NestedFamily;
193 else if ((ModFlags & Modifiers.INTERNAL) != 0)
194 x |= TypeAttributes.NestedAssembly;
195 else if ((ModFlags & Modifiers.PUBLIC) != 0)
196 x |= TypeAttributes.NestedPublic;
198 x |= TypeAttributes.NestedPrivate;
200 if ((ModFlags & Modifiers.PUBLIC) != 0)
201 x |= TypeAttributes.Public;
202 else if ((ModFlags & Modifiers.PRIVATE) != 0)
203 x |= TypeAttributes.NotPublic;
206 if ((ModFlags & Modifiers.ABSTRACT) != 0)
207 x |= TypeAttributes.Abstract;
209 if ((ModFlags & Modifiers.SEALED) != 0)
210 x |= TypeAttributes.Sealed;
216 void Error111 (InterfaceMemberBase ib)
220 "Interface `" + Name + "' already contains a definition with the " +
221 "same return value and parameter types for member `" + ib.Name + "'");
224 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
226 if (!TypeManager.RegisterMethod (mb, ip, types))
229 method_builders.Add (mb);
234 // This might trigger a definition of the methods. This happens only
235 // with Attributes, as Attribute classes are processed before interfaces.
236 // Ideally, we should make everything just define recursively in terms
237 // of its dependencies.
239 public MethodInfo [] GetMethods (TypeContainer container)
243 if (!members_defined){
244 if (DefineMembers (container))
245 n = method_builders.Count;
247 n = method_builders.Count;
249 MethodInfo [] mi = new MethodInfo [n];
251 method_builders.CopyTo (mi, 0);
256 // Hack around System.Reflection as found everywhere else
257 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
258 MemberFilter filter, object criteria)
260 ArrayList members = new ArrayList ();
262 if ((mt & MemberTypes.Method) != 0) {
263 foreach (MethodBuilder mb in method_builders)
264 if (filter (mb, criteria))
268 if ((mt & MemberTypes.Property) != 0) {
269 foreach (PropertyBuilder pb in property_builders)
270 if (filter (pb, criteria))
274 if ((mt & MemberTypes.Event) != 0) {
275 foreach (MyEventBuilder eb in event_builders)
276 if (filter (eb, criteria))
280 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
281 MemberList parent_mi;
283 parent_mi = TypeContainer.FindMembers (
284 TypeBuilder.BaseType, mt, bf, filter, criteria);
286 members.AddRange (parent_mi);
289 return new MemberList (members);
292 public override MemberCache MemberCache {
299 // Populates the methods in the interface
301 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
303 Type return_type = im.ReturnType.Type;
304 if (return_type == null)
305 return_type = this.ResolveType (im.ReturnType, false, im.Location);
307 Type [] arg_types = im.ParameterTypes (this);
312 if (return_type == null)
315 if (return_type.IsPointer && !UnsafeOK (this))
318 if (arg_types == null)
321 foreach (Type t in arg_types){
326 if (t.IsPointer && !UnsafeOK (this))
333 mb = TypeBuilder.DefineMethod (
334 im.Name, interface_method_attributes,
335 return_type, arg_types);
337 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
339 if (!RegisterMethod (mb, ip, arg_types)) {
345 // Define each type attribute (in/out/ref) and
346 // the argument names.
348 p = im.Parameters.FixedParameters;
350 for (i = 0; i < p.Length; i++)
351 mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
353 if (i != arg_types.Length)
354 Console.WriteLine ("Implement the type definition for params");
362 // Populates the properties in the interface
364 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
367 MethodBuilder get = null, set = null;
368 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
372 Type prop_type = ip.Type.Type;
373 Type [] setter_args = new Type [1];
375 if (prop_type == null)
378 if (prop_type.IsPointer && !UnsafeOK (this))
381 setter_args [0] = prop_type;
384 // FIXME: properties are missing the following
385 // flags: hidebysig newslot specialname
387 pb = TypeBuilder.DefineProperty (
388 ip.Name, PropertyAttributes.None,
392 get = TypeBuilder.DefineMethod (
393 "get_" + ip.Name, property_attributes ,
397 // HACK because System.Reflection.Emit is lame
399 Type [] null_types = null;
400 InternalParameters inp = new InternalParameters
401 (null_types, Parameters.EmptyReadOnlyParameters);
403 if (!RegisterMethod (get, inp, null)) {
408 pb.SetGetMethod (get);
412 setter_args [0] = prop_type;
414 set = TypeBuilder.DefineMethod (
415 "set_" + ip.Name, property_attributes,
416 TypeManager.void_type, setter_args);
418 set.DefineParameter (1, ParameterAttributes.None, "value");
419 pb.SetSetMethod (set);
422 // HACK because System.Reflection.Emit is lame
424 Parameter [] parms = new Parameter [1];
425 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
426 InternalParameters ipp = new InternalParameters (
427 this, new Parameters (parms, null, Location.Null));
429 if (!RegisterMethod (set, ipp, setter_args)) {
435 TypeManager.RegisterProperty (pb, get, set);
436 property_builders.Add (pb);
441 // Populates the events in the interface
443 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
446 // FIXME: We need to do this after delegates have been
447 // declared or we declare them recursively.
450 MethodBuilder add = null, remove = null;
451 ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
455 Type event_type = ie.Type.Type;
457 if (event_type == null)
460 if (event_type.IsPointer && !UnsafeOK (this))
463 Type [] parameters = new Type [1];
464 parameters [0] = event_type;
466 eb = new MyEventBuilder (null, TypeBuilder, ie.Name,
467 EventAttributes.None, event_type);
470 // Now define the accessors
472 string add_name = "add_" + ie.Name;
474 add = TypeBuilder.DefineMethod (
475 add_name, property_attributes, null, parameters);
476 add.DefineParameter (1, ParameterAttributes.None, "value");
477 eb.SetAddOnMethod (add);
479 string remove_name = "remove_" + ie.Name;
480 remove = TypeBuilder.DefineMethod (
481 remove_name, property_attributes, null, parameters);
482 remove.DefineParameter (1, ParameterAttributes.None, "value");
483 eb.SetRemoveOnMethod (remove);
485 Parameter [] parms = new Parameter [1];
486 parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
487 InternalParameters ip = new InternalParameters (
488 this, new Parameters (parms, null, Location.Null));
490 if (!RegisterMethod (add, ip, parameters)) {
495 if (!RegisterMethod (remove, ip, parameters)) {
500 TypeManager.RegisterEvent (eb, add, remove);
501 event_builders.Add (eb);
507 // Populates the indexers in the interface
509 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
512 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
516 Type prop_type = ii.Type.Type;
517 Type [] arg_types = ii.ParameterTypes (this);
518 Type [] value_arg_types;
520 if (prop_type == null)
523 if (prop_type.IsPointer && !UnsafeOK (this))
527 // Sets up the extra invisible `value' argument for setters.
529 if (arg_types != null){
530 int count = arg_types.Length;
531 value_arg_types = new Type [count + 1];
533 arg_types.CopyTo (value_arg_types, 0);
534 value_arg_types [count] = prop_type;
536 foreach (Type t in arg_types){
537 if (t.IsPointer && !UnsafeOK (this))
541 value_arg_types = new Type [1];
543 value_arg_types [1] = prop_type;
546 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
547 null, ModFlags, false);
549 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
550 if (IndexerName == null)
551 IndexerName = "Item";
553 pb = TypeBuilder.DefineProperty (
554 IndexerName, PropertyAttributes.None,
555 prop_type, arg_types);
557 MethodBuilder set_item = null, get_item = null;
559 Parameter [] p = ii.Parameters.FixedParameters;
561 get_item = TypeBuilder.DefineMethod (
562 "get_" + IndexerName, property_attributes,
563 prop_type, arg_types);
564 pb.SetGetMethod (get_item);
566 // HACK because System.Reflection.Emit is lame
568 InternalParameters ip = new InternalParameters (
569 arg_types, ii.Parameters);
571 if (!RegisterMethod (get_item, ip, arg_types)) {
577 for (int i = 0; i < p.Length; i++)
578 get_item.DefineParameter (
580 p [i].Attributes, p [i].Name);
585 Parameter [] p = ii.Parameters.FixedParameters;
589 pv = new Parameter [p.Length + 1];
591 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
592 Parameters value_params = new Parameters (pv, null, Location.Null);
593 value_params.GetParameterInfo (decl_space);
595 set_item = TypeBuilder.DefineMethod (
596 "set_" + IndexerName, property_attributes,
597 TypeManager.void_type, value_arg_types);
598 pb.SetSetMethod (set_item);
600 // HACK because System.Reflection.Emit is lame
602 InternalParameters ip = new InternalParameters (
603 value_arg_types, value_params);
604 if (!RegisterMethod (set_item, ip, value_arg_types)) {
610 for (; i < p.Length; i++)
611 set_item.DefineParameter (
613 p [i].Attributes, p [i].Name);
616 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
619 property_builders.Add (pb);
625 /// Performs the semantic analysis for all the interface members
626 /// that were declared
628 bool SemanticAnalysis ()
630 Hashtable methods = new Hashtable ();
633 if (defined_method != null){
634 foreach (InterfaceMethod im in defined_method){
635 string sig = im.GetSignature (this);
638 // If there was an undefined Type on the signatures
643 if (methods [sig] != null){
651 // FIXME: Here I should check i
656 Type GetInterfaceTypeByName (Expression name)
658 Expression original = name;
659 name = ResolveTypeExpr (name, false, Location);
671 cause = "is a struct";
673 cause = "is a class";
675 cause = "Should not happen.";
677 Report.Error (527, Location, "`"+name+"' " + cause +
678 ", need an interface instead");
684 // Returns the list of interfaces that this interface implements
685 // Or null if it does not implement any interface.
687 // Sets the error boolean accoringly.
689 Type [] GetInterfaceBases (out bool error)
698 tbases = new Type [Bases.Count];
701 foreach (Expression name in Bases){
704 t = GetInterfaceTypeByName (name);
710 if (!Parent.AsAccessible (t, ModFlags))
711 Report.Error (61, Location,
712 "Inconsistent accessibility: base interface `" +
713 TypeManager.CSharpName (t) + "' is less " +
714 "accessible than interface `" +
720 return TypeManager.ExpandInterfaces (tbases);
725 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
729 // Rework the way we recurse, because for recursive
730 // definitions of interfaces (A:B and B:A) we report the
731 // error twice, rather than once.
733 public override TypeBuilder DefineType ()
738 if (TypeBuilder != null)
746 ifaces = GetInterfaceBases (out error);
752 if (TypeManager.NamespaceClash (Name, Location))
755 ModuleBuilder builder = CodeGen.ModuleBuilder;
757 TypeBuilder = builder.DefineType (
760 (Type)null, // Parent Type
762 RootContext.RegisterOrder (this);
764 TypeBuilder builder = Parent.TypeBuilder;
766 TypeBuilder = builder.DefineNestedType (
769 (Type) null, //parent type
772 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
773 tc.RegisterOrder (this);
776 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
783 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
784 // interface is consistent. Either it is `Item' or it is the name defined by all the
785 // indexers with the `IndexerName' attribute.
787 // Turns out that the IndexerNameAttribute is applied to each indexer,
788 // but it is never emitted, instead a DefaultName attribute is attached
791 void DefineIndexers (TypeContainer parent)
793 string interface_indexer_name = null;
795 foreach (InterfaceIndexer ii in defined_indexer){
797 PopulateIndexer (parent, this, ii);
799 if (interface_indexer_name == null){
800 interface_indexer_name = IndexerName;
804 if (IndexerName == interface_indexer_name)
808 668, "Two indexers have different names, " +
809 " you should use the same name for all your indexers");
811 if (interface_indexer_name == null)
812 interface_indexer_name = "Item";
813 IndexerName = interface_indexer_name;
817 /// Performs semantic analysis, and then generates the IL interfaces
819 public override bool DefineMembers (TypeContainer parent)
824 if (!SemanticAnalysis ())
828 if (defined_method != null){
829 foreach (InterfaceMethod im in defined_method)
830 PopulateMethod (parent, this, im);
833 if (defined_properties != null){
834 foreach (InterfaceProperty ip in defined_properties)
835 PopulateProperty (parent, this, ip);
838 if (defined_events != null)
839 foreach (InterfaceEvent ie in defined_events)
840 PopulateEvent (parent, this, ie);
842 if (defined_indexer != null) {
843 DefineIndexers (parent);
845 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
846 parent, IndexerName, ModFlags, Location);
848 TypeBuilder.SetCustomAttribute (cb);
852 if (TypeBuilder.BaseType != null)
853 parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
855 member_cache = new MemberCache (this);
857 members_defined = true;
863 // In the case of Interfaces, there is nothing to do here
865 public override bool Define (TypeContainer parent)
871 /// Applies all the attributes.
873 public void Emit (TypeContainer tc)
875 if (OptAttributes != null) {
876 EmitContext ec = new EmitContext (tc, this, Location, null, null,
878 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
881 // Now emit attributes for each interface member
882 if (defined_method != null) {
883 foreach (InterfaceMethod im in defined_method) {
884 EmitContext ec = new EmitContext (tc, this, Location, null,
885 im.ReturnType.Type, ModFlags, false);
887 if (im.OptAttributes != null)
888 Attribute.ApplyAttributes (ec, im.Builder, im, im.OptAttributes);
892 if (defined_properties != null) {
893 foreach (InterfaceProperty ip in defined_properties) {
894 EmitContext ec = new EmitContext (tc, this, Location, null,
895 null, ModFlags, false);
897 if (ip.OptAttributes != null)
898 Attribute.ApplyAttributes (ec, ip.Builder, ip, ip.OptAttributes);
902 if (defined_events != null) {
903 foreach (InterfaceEvent ie in defined_events) {
904 EmitContext ec = new EmitContext (tc, this, Location, null,
905 null, ModFlags, false);
907 if (ie.OptAttributes != null)
908 Attribute.ApplyAttributes (ec, ie.Builder, ie, ie.OptAttributes);
913 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
918 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
920 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
921 ".ctor", MemberTypes.Constructor,
922 BindingFlags.Public | BindingFlags.Instance,
925 if (!(ml is MethodGroupExpr)) {
926 Console.WriteLine ("Internal error !!!!");
930 MethodGroupExpr mg = (MethodGroupExpr) ml;
932 MethodBase constructor = mg.Methods [0];
934 string [] vals = { name };
936 CustomAttributeBuilder cb = null;
938 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
940 Report.Warning (-100, "Can not set the indexer default member attribute");
950 string IMemberContainer.Name {
956 Type IMemberContainer.Type {
962 IMemberContainer IMemberContainer.Parent {
964 return parent_container;
968 MemberCache IMemberContainer.MemberCache {
974 bool IMemberContainer.IsInterface {
980 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
982 // Interfaces only contain instance members.
983 if ((bf & BindingFlags.Instance) == 0)
984 return MemberList.Empty;
985 if ((bf & BindingFlags.Public) == 0)
986 return MemberList.Empty;
988 ArrayList members = new ArrayList ();
990 if ((mt & MemberTypes.Method) != 0)
991 members.AddRange (method_builders);
993 if ((mt & MemberTypes.Property) != 0)
994 members.AddRange (property_builders);
996 if ((mt & MemberTypes.Event) != 0)
997 members.AddRange (event_builders);
999 return new MemberList (members);
1003 public class InterfaceMemberBase {
1004 public readonly string Name;
1005 public readonly bool IsNew;
1006 public Attributes OptAttributes;
1008 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
1012 OptAttributes = attrs;
1016 public class InterfaceProperty : InterfaceMemberBase {
1017 public readonly bool HasSet;
1018 public readonly bool HasGet;
1019 public readonly Location Location;
1020 public Expression Type;
1021 public PropertyBuilder Builder;
1023 public InterfaceProperty (Expression type, string name,
1024 bool is_new, bool has_get, bool has_set,
1025 Attributes attrs, Location loc)
1026 : base (name, is_new, attrs)
1035 public class InterfaceEvent : InterfaceMemberBase {
1036 public readonly Location Location;
1037 public Expression Type;
1038 public MyEventBuilder Builder;
1040 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
1042 : base (name, is_new, attrs)
1049 public class InterfaceMethod : InterfaceMemberBase {
1050 public Expression ReturnType;
1051 public readonly Parameters Parameters;
1052 public readonly Location Location;
1053 public MethodBuilder Builder;
1055 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
1056 Attributes attrs, Location l)
1057 : base (name, is_new, attrs)
1059 this.ReturnType = return_type;
1060 this.Parameters = args;
1065 /// Returns the signature for this interface method
1067 public string GetSignature (DeclSpace ds)
1069 ReturnType = ds.ResolveTypeExpr (ReturnType, false, Location);
1070 if (ReturnType == null)
1073 Type ret = ReturnType.Type;
1074 string args = Parameters.GetSignature (ds);
1076 if ((ret == null) || (args == null))
1079 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
1082 public Type [] ParameterTypes (DeclSpace ds)
1084 return Parameters.GetParameterInfo (ds);
1088 public class InterfaceIndexer : InterfaceMemberBase {
1089 public readonly bool HasGet, HasSet;
1090 public readonly Parameters Parameters;
1091 public readonly Location Location;
1092 public Expression Type;
1093 public PropertyBuilder Builder;
1095 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
1096 bool is_new, Attributes attrs, Location loc)
1097 : base ("", is_new, attrs)
1106 public Type [] ParameterTypes (DeclSpace ds)
1108 return Parameters.GetParameterInfo (ds);