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 (NamespaceEntry ns, TypeContainer parent, string name, int mod,
75 Attributes attrs, Location l)
76 : base (ns, parent, name, l)
78 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
79 OptAttributes = attrs;
81 method_builders = new ArrayList ();
82 property_builders = new ArrayList ();
83 event_builders = new ArrayList ();
86 public AdditionResult AddMethod (InterfaceMethod imethod)
88 string name = imethod.Name;
89 Object value = defined_names [name];
92 if (!(value is InterfaceMethod))
93 return AdditionResult.NameExists;
96 if (defined_method == null)
97 defined_method = new ArrayList ();
99 defined_method.Add (imethod);
101 DefineName (name, imethod);
103 return AdditionResult.Success;
106 public AdditionResult AddProperty (InterfaceProperty iprop)
109 string name = iprop.Name;
111 if ((res = IsValid (name, name)) != AdditionResult.Success)
114 DefineName (name, iprop);
116 if (defined_properties == null)
117 defined_properties = new ArrayList ();
119 defined_properties.Add (iprop);
120 return AdditionResult.Success;
123 public AdditionResult AddEvent (InterfaceEvent ievent)
125 string name = ievent.Name;
128 if ((res = IsValid (name, name)) != AdditionResult.Success)
131 DefineName (name, ievent);
133 if (defined_events == null)
134 defined_events = new ArrayList ();
136 defined_events.Add (ievent);
137 return AdditionResult.Success;
140 public bool AddIndexer (InterfaceIndexer iindexer)
142 if (defined_indexer == null)
143 defined_indexer = new ArrayList ();
145 defined_indexer.Add (iindexer);
149 public ArrayList InterfaceMethods {
151 return defined_method;
155 public ArrayList InterfaceProperties {
157 return defined_properties;
161 public ArrayList InterfaceEvents {
163 return defined_events;
167 public ArrayList InterfaceIndexers {
169 return defined_indexer;
173 public ArrayList Bases {
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);
235 // This might trigger a definition of the methods. This happens only
236 // with Attributes, as Attribute classes are processed before interfaces.
237 // Ideally, we should make everything just define recursively in terms
238 // of its dependencies.
240 public MethodInfo [] GetMethods (TypeContainer container)
244 if (!members_defined){
245 if (DefineMembers (container))
246 n = method_builders.Count;
248 n = method_builders.Count;
250 MethodInfo [] mi = new MethodInfo [n];
252 method_builders.CopyTo (mi, 0);
257 // Hack around System.Reflection as found everywhere else
258 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
259 MemberFilter filter, object criteria)
261 ArrayList members = new ArrayList ();
263 if ((mt & MemberTypes.Method) != 0) {
264 foreach (MethodBuilder mb in method_builders)
265 if (filter (mb, criteria))
269 if ((mt & MemberTypes.Property) != 0) {
270 foreach (PropertyBuilder pb in property_builders)
271 if (filter (pb, criteria))
275 if ((mt & MemberTypes.Event) != 0) {
276 foreach (MyEventBuilder eb in event_builders)
277 if (filter (eb, criteria))
281 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
282 MemberList parent_mi;
284 parent_mi = TypeContainer.FindMembers (
285 TypeBuilder.BaseType, mt, bf, filter, criteria);
287 members.AddRange (parent_mi);
290 return new MemberList (members);
293 public override MemberCache MemberCache {
300 // Populates the methods in the interface
302 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
304 Type return_type = im.ReturnType.Type;
305 if (return_type == null)
306 return_type = this.ResolveType (im.ReturnType, false, im.Location);
308 Type [] arg_types = im.ParameterTypes (this);
311 if (return_type == null)
314 if (return_type.IsPointer && !UnsafeOK (this))
317 if (arg_types == null)
320 foreach (Type t in arg_types){
325 if (t.IsPointer && !UnsafeOK (this))
332 mb = TypeBuilder.DefineMethod (
333 im.Name, interface_method_attributes,
334 return_type, arg_types);
336 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
338 if (!RegisterMethod (mb, ip, arg_types)) {
344 // Labelling of parameters is taken care of
345 // during the Emit phase via
346 // MethodCore.LabelParameters method so I am
347 // removing the old code here.
355 // Populates the properties in the interface
357 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
360 MethodBuilder get = null, set = null;
361 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
365 Type prop_type = ip.Type.Type;
366 Type [] setter_args = new Type [1];
368 if (prop_type == null)
371 if (prop_type.IsPointer && !UnsafeOK (this))
374 setter_args [0] = prop_type;
377 // FIXME: properties are missing the following
378 // flags: hidebysig newslot specialname
380 pb = TypeBuilder.DefineProperty (
381 ip.Name, PropertyAttributes.None,
385 get = TypeBuilder.DefineMethod (
386 "get_" + ip.Name, property_attributes ,
390 // HACK because System.Reflection.Emit is lame
392 Type [] null_types = null;
393 InternalParameters inp = new InternalParameters
394 (null_types, Parameters.EmptyReadOnlyParameters);
396 if (!RegisterMethod (get, inp, null)) {
401 pb.SetGetMethod (get);
405 setter_args [0] = prop_type;
407 set = TypeBuilder.DefineMethod (
408 "set_" + ip.Name, property_attributes,
409 TypeManager.void_type, setter_args);
411 set.DefineParameter (1, ParameterAttributes.None, "value");
412 pb.SetSetMethod (set);
415 // HACK because System.Reflection.Emit is lame
417 Parameter [] parms = new Parameter [1];
418 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
419 InternalParameters ipp = new InternalParameters (
420 this, new Parameters (parms, null, Location.Null));
422 if (!RegisterMethod (set, ipp, setter_args)) {
428 TypeManager.RegisterProperty (pb, get, set);
429 property_builders.Add (pb);
434 // Populates the events in the interface
436 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
439 // FIXME: We need to do this after delegates have been
440 // declared or we declare them recursively.
443 MethodBuilder add = null, remove = null;
444 ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
448 Type event_type = ie.Type.Type;
450 if (event_type == null)
453 if (event_type.IsPointer && !UnsafeOK (this))
456 Type [] parameters = new Type [1];
457 parameters [0] = event_type;
459 eb = new MyEventBuilder (null, TypeBuilder, ie.Name,
460 EventAttributes.None, event_type);
463 // Now define the accessors
465 string add_name = "add_" + ie.Name;
467 add = TypeBuilder.DefineMethod (
468 add_name, property_attributes, null, parameters);
469 add.DefineParameter (1, ParameterAttributes.None, "value");
470 eb.SetAddOnMethod (add);
472 string remove_name = "remove_" + ie.Name;
473 remove = TypeBuilder.DefineMethod (
474 remove_name, property_attributes, null, parameters);
475 remove.DefineParameter (1, ParameterAttributes.None, "value");
476 eb.SetRemoveOnMethod (remove);
478 Parameter [] parms = new Parameter [1];
479 parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
480 InternalParameters ip = new InternalParameters (
481 this, new Parameters (parms, null, Location.Null));
483 if (!RegisterMethod (add, ip, parameters)) {
488 if (!RegisterMethod (remove, ip, parameters)) {
493 TypeManager.RegisterEvent (eb, add, remove);
494 event_builders.Add (eb);
500 // Populates the indexers in the interface
502 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
505 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
509 Type prop_type = ii.Type.Type;
510 Type [] arg_types = ii.ParameterTypes (this);
511 Type [] value_arg_types;
513 if (prop_type == null)
516 if (prop_type.IsPointer && !UnsafeOK (this))
520 // Sets up the extra invisible `value' argument for setters.
522 if (arg_types != null){
523 int count = arg_types.Length;
524 value_arg_types = new Type [count + 1];
526 arg_types.CopyTo (value_arg_types, 0);
527 value_arg_types [count] = prop_type;
529 foreach (Type t in arg_types){
530 if (t.IsPointer && !UnsafeOK (this))
534 value_arg_types = new Type [1];
536 value_arg_types [1] = prop_type;
539 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
540 null, ModFlags, false);
542 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
543 if (IndexerName == null)
544 IndexerName = "Item";
546 pb = TypeBuilder.DefineProperty (
547 IndexerName, PropertyAttributes.None,
548 prop_type, arg_types);
550 MethodBuilder set_item = null, get_item = null;
552 Parameter [] p = ii.Parameters.FixedParameters;
554 get_item = TypeBuilder.DefineMethod (
555 "get_" + IndexerName, property_attributes,
556 prop_type, arg_types);
557 pb.SetGetMethod (get_item);
559 // HACK because System.Reflection.Emit is lame
561 InternalParameters ip = new InternalParameters (
562 arg_types, ii.Parameters);
564 if (!RegisterMethod (get_item, ip, arg_types)) {
570 for (int i = 0; i < p.Length; i++)
571 get_item.DefineParameter (
573 p [i].Attributes, p [i].Name);
578 Parameter [] p = ii.Parameters.FixedParameters;
582 pv = new Parameter [p.Length + 1];
584 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
585 Parameters value_params = new Parameters (pv, null, Location.Null);
586 value_params.GetParameterInfo (decl_space);
588 set_item = TypeBuilder.DefineMethod (
589 "set_" + IndexerName, property_attributes,
590 TypeManager.void_type, value_arg_types);
591 pb.SetSetMethod (set_item);
593 // HACK because System.Reflection.Emit is lame
595 InternalParameters ip = new InternalParameters (
596 value_arg_types, value_params);
597 if (!RegisterMethod (set_item, ip, value_arg_types)) {
603 for (; i < p.Length; i++)
604 set_item.DefineParameter (
606 p [i].Attributes, p [i].Name);
609 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
612 property_builders.Add (pb);
618 /// Performs the semantic analysis for all the interface members
619 /// that were declared
621 bool SemanticAnalysis ()
623 Hashtable methods = new Hashtable ();
626 if (defined_method != null){
627 foreach (InterfaceMethod im in defined_method){
628 string sig = im.GetSignature (this);
631 // If there was an undefined Type on the signatures
636 if (methods [sig] != null){
644 // FIXME: Here I should check i
649 TypeExpr GetInterfaceTypeByName (Expression name)
651 TypeExpr resolved = ResolveTypeExpr (name, false, Location);
652 if (resolved == null)
655 if (resolved.IsInterface)
660 if (resolved.IsValueType)
661 cause = "is a struct";
662 else if (resolved.IsClass)
663 cause = "is a class";
665 cause = "Should not happen.";
667 Report.Error (527, Location, "`"+resolved.Name+"' " + cause +
668 ", need an interface instead");
674 // Returns the list of interfaces that this interface implements
675 // Or null if it does not implement any interface.
677 // Sets the error boolean accoringly.
679 TypeExpr [] GetInterfaceBases (out bool error)
688 tbases = new TypeExpr [Bases.Count];
691 foreach (Expression name in Bases){
694 t = GetInterfaceTypeByName (name);
700 if (!t.AsAccessible (Parent, ModFlags))
701 Report.Error (61, Location,
702 "Inconsistent accessibility: base interface `" +
703 t.Name + "' is less accessible than interface `" +
709 return TypeManager.ExpandInterfaces (tbases);
714 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
718 // Rework the way we recurse, because for recursive
719 // definitions of interfaces (A:B and B:A) we report the
720 // error twice, rather than once.
722 public override TypeBuilder DefineType ()
727 if (TypeBuilder != null)
735 EmitContext ec = new EmitContext (this, this, Location, null, null,
738 ifaces = GetInterfaceBases (out error);
744 foreach (TypeParameter type_param in TypeParameters)
745 if (!type_param.Resolve (this)) {
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);
777 foreach (TypeParameter type_param in TypeParameters)
778 type_param.Define (TypeBuilder);
780 foreach (TypeParameter type_param in TypeParameters)
781 type_param.DefineType (ec, TypeBuilder);
784 if (ifaces != null) {
785 foreach (TypeExpr iface in ifaces) {
786 Type itype = iface.ResolveType (ec);
787 TypeBuilder.AddInterfaceImplementation (itype);
791 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
798 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
799 // interface is consistent. Either it is `Item' or it is the name defined by all the
800 // indexers with the `IndexerName' attribute.
802 // Turns out that the IndexerNameAttribute is applied to each indexer,
803 // but it is never emitted, instead a DefaultName attribute is attached
806 void DefineIndexers (TypeContainer parent)
808 string interface_indexer_name = null;
810 foreach (InterfaceIndexer ii in defined_indexer){
812 PopulateIndexer (parent, this, ii);
814 if (interface_indexer_name == null){
815 interface_indexer_name = IndexerName;
819 if (IndexerName == interface_indexer_name)
823 668, "Two indexers have different names, " +
824 " you should use the same name for all your indexers");
826 if (interface_indexer_name == null)
827 interface_indexer_name = "Item";
828 IndexerName = interface_indexer_name;
832 /// Performs semantic analysis, and then generates the IL interfaces
834 public override bool DefineMembers (TypeContainer parent)
839 if (!SemanticAnalysis ())
843 if (defined_method != null){
844 foreach (InterfaceMethod im in defined_method)
845 PopulateMethod (parent, this, im);
848 if (defined_properties != null){
849 foreach (InterfaceProperty ip in defined_properties)
850 PopulateProperty (parent, this, ip);
853 if (defined_events != null)
854 foreach (InterfaceEvent ie in defined_events)
855 PopulateEvent (parent, this, ie);
857 if (defined_indexer != null) {
858 DefineIndexers (parent);
860 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
861 parent, IndexerName, ModFlags, Location);
863 TypeBuilder.SetCustomAttribute (cb);
867 if (TypeBuilder.BaseType != null)
868 parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
870 member_cache = new MemberCache (this);
872 members_defined = true;
878 // In the case of Interfaces, there is nothing to do here
880 public override bool Define (TypeContainer parent)
886 /// Applies all the attributes.
888 public void Emit (TypeContainer tc)
890 if (OptAttributes != null) {
891 EmitContext ec = new EmitContext (tc, this, Location, null, null,
893 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
896 // Now emit attributes for each interface member
897 if (defined_method != null) {
898 foreach (InterfaceMethod im in defined_method) {
899 EmitContext ec = new EmitContext (tc, this, Location, null,
900 im.ReturnType.Type, ModFlags, false);
902 MethodCore.LabelParameters (ec, im.Builder,
907 if (im.OptAttributes != null)
908 Attribute.ApplyAttributes (ec, im.Builder,
909 im, im.OptAttributes);
914 if (defined_properties != null) {
915 foreach (InterfaceProperty ip in defined_properties) {
916 EmitContext ec = new EmitContext (tc, this, Location, null,
917 null, ModFlags, false);
919 if (ip.OptAttributes != null)
920 Attribute.ApplyAttributes (ec, ip.Builder, ip, ip.OptAttributes);
924 if (defined_events != null) {
925 foreach (InterfaceEvent ie in defined_events) {
926 EmitContext ec = new EmitContext (tc, this, Location, null,
927 null, ModFlags, false);
929 if (ie.OptAttributes != null)
930 Attribute.ApplyAttributes (ec, ie.Builder, ie, ie.OptAttributes);
935 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
940 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
942 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
943 ".ctor", MemberTypes.Constructor,
944 BindingFlags.Public | BindingFlags.Instance,
947 if (!(ml is MethodGroupExpr)) {
948 Console.WriteLine ("Internal error !!!!");
952 MethodGroupExpr mg = (MethodGroupExpr) ml;
954 MethodBase constructor = mg.Methods [0];
956 string [] vals = { name };
958 CustomAttributeBuilder cb = null;
960 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
962 Report.Warning (-100, "Can not set the indexer default member attribute");
972 string IMemberContainer.Name {
978 Type IMemberContainer.Type {
984 IMemberContainer IMemberContainer.Parent {
986 return parent_container;
990 MemberCache IMemberContainer.MemberCache {
996 bool IMemberContainer.IsInterface {
1002 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
1004 // Interfaces only contain instance members.
1005 if ((bf & BindingFlags.Instance) == 0)
1006 return MemberList.Empty;
1007 if ((bf & BindingFlags.Public) == 0)
1008 return MemberList.Empty;
1010 ArrayList members = new ArrayList ();
1012 if ((mt & MemberTypes.Method) != 0)
1013 members.AddRange (method_builders);
1015 if ((mt & MemberTypes.Property) != 0)
1016 members.AddRange (property_builders);
1018 if ((mt & MemberTypes.Event) != 0)
1019 members.AddRange (event_builders);
1021 return new MemberList (members);
1025 public class InterfaceMemberBase {
1026 public readonly string Name;
1027 public readonly bool IsNew;
1028 public Attributes OptAttributes;
1030 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
1034 OptAttributes = attrs;
1038 public class InterfaceProperty : InterfaceMemberBase {
1039 public readonly bool HasSet;
1040 public readonly bool HasGet;
1041 public readonly Location Location;
1042 public Expression Type;
1043 public PropertyBuilder Builder;
1045 public InterfaceProperty (Expression type, string name,
1046 bool is_new, bool has_get, bool has_set,
1047 Attributes attrs, Location loc)
1048 : base (name, is_new, attrs)
1057 public class InterfaceEvent : InterfaceMemberBase {
1058 public readonly Location Location;
1059 public Expression Type;
1060 public MyEventBuilder Builder;
1062 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
1064 : base (name, is_new, attrs)
1071 public class InterfaceMethod : InterfaceMemberBase {
1072 public Expression ReturnType;
1073 public readonly Parameters Parameters;
1074 public readonly Location Location;
1075 public MethodBuilder Builder;
1077 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
1078 Attributes attrs, Location l)
1079 : base (name, is_new, attrs)
1081 this.ReturnType = return_type;
1082 this.Parameters = args;
1087 /// Returns the signature for this interface method
1089 public string GetSignature (DeclSpace ds)
1091 ReturnType = ds.ResolveTypeExpr (ReturnType, false, Location);
1092 if (ReturnType == null)
1095 Type ret = ReturnType.Type;
1096 string args = Parameters.GetSignature (ds);
1098 if ((ret == null) || (args == null))
1101 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
1104 public Type [] ParameterTypes (DeclSpace ds)
1106 return Parameters.GetParameterInfo (ds);
1110 public class InterfaceIndexer : InterfaceMemberBase {
1111 public readonly bool HasGet, HasSet;
1112 public readonly Parameters Parameters;
1113 public readonly Location Location;
1114 public Expression Type;
1115 public PropertyBuilder Builder;
1117 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
1118 bool is_new, Attributes attrs, Location loc)
1119 : base ("", is_new, attrs)
1128 public Type [] ParameterTypes (DeclSpace ds)
1130 return Parameters.GetParameterInfo (ds);