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;
50 public string IndexerName;
52 IMemberContainer parent_container;
53 MemberCache member_cache;
57 // These will happen after the semantic analysis
59 // Hashtable defined_indexers;
60 // Hashtable defined_methods;
63 /// Modifiers allowed in a class declaration
65 public const int AllowedModifiers =
73 public Interface (NamespaceEntry ns, TypeContainer parent, string name, int mod,
74 Attributes attrs, Location l)
75 : base (ns, parent, name, attrs, l)
77 ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
79 method_builders = new ArrayList ();
80 property_builders = new ArrayList ();
81 event_builders = new ArrayList ();
84 public AdditionResult AddMethod (InterfaceMethod imethod)
86 string name = imethod.Name;
87 Object value = defined_names [name];
90 if (!(value is InterfaceMethod))
91 return AdditionResult.NameExists;
94 if (defined_method == null)
95 defined_method = new ArrayList ();
97 defined_method.Add (imethod);
99 DefineName (name, imethod);
101 return AdditionResult.Success;
104 public AdditionResult AddProperty (InterfaceProperty iprop)
107 string name = iprop.Name;
109 if ((res = IsValid (name, name)) != AdditionResult.Success)
112 DefineName (name, iprop);
114 if (defined_properties == null)
115 defined_properties = new ArrayList ();
117 defined_properties.Add (iprop);
118 return AdditionResult.Success;
121 public AdditionResult AddEvent (InterfaceEvent ievent)
123 string name = ievent.Name;
126 if ((res = IsValid (name, name)) != AdditionResult.Success)
129 DefineName (name, ievent);
131 if (defined_events == null)
132 defined_events = new ArrayList ();
134 defined_events.Add (ievent);
135 return AdditionResult.Success;
138 public bool AddIndexer (InterfaceIndexer iindexer)
140 if (defined_indexer == null)
141 defined_indexer = new ArrayList ();
143 defined_indexer.Add (iindexer);
147 public ArrayList InterfaceMethods {
149 return defined_method;
153 public ArrayList InterfaceProperties {
155 return defined_properties;
159 public ArrayList InterfaceEvents {
161 return defined_events;
165 public ArrayList InterfaceIndexers {
167 return defined_indexer;
171 public ArrayList Bases {
181 public virtual TypeAttributes InterfaceAttr {
183 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
185 if (IsTopLevel == false) {
187 if ((ModFlags & Modifiers.PROTECTED) != 0
188 && (ModFlags & Modifiers.INTERNAL) != 0)
189 x |= TypeAttributes.NestedFamORAssem;
190 else if ((ModFlags & Modifiers.PROTECTED) != 0)
191 x |= TypeAttributes.NestedFamily;
192 else if ((ModFlags & Modifiers.INTERNAL) != 0)
193 x |= TypeAttributes.NestedAssembly;
194 else if ((ModFlags & Modifiers.PUBLIC) != 0)
195 x |= TypeAttributes.NestedPublic;
197 x |= TypeAttributes.NestedPrivate;
199 if ((ModFlags & Modifiers.PUBLIC) != 0)
200 x |= TypeAttributes.Public;
201 else if ((ModFlags & Modifiers.PRIVATE) != 0)
202 x |= TypeAttributes.NotPublic;
205 if ((ModFlags & Modifiers.ABSTRACT) != 0)
206 x |= TypeAttributes.Abstract;
208 if ((ModFlags & Modifiers.SEALED) != 0)
209 x |= TypeAttributes.Sealed;
215 void Error111 (InterfaceMemberBase ib)
219 "Interface `" + Name + "' already contains a definition with the " +
220 "same return value and parameter types for member `" + ib.Name + "'");
223 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
225 if (!TypeManager.RegisterMethod (mb, ip, types))
228 method_builders.Add (mb);
233 // This might trigger a definition of the methods. This happens only
234 // with Attributes, as Attribute classes are processed before interfaces.
235 // Ideally, we should make everything just define recursively in terms
236 // of its dependencies.
238 public MethodInfo [] GetMethods (TypeContainer container)
242 if (!members_defined){
243 if (DefineMembers (container))
244 n = method_builders.Count;
246 n = method_builders.Count;
248 MethodInfo [] mi = new MethodInfo [n];
250 method_builders.CopyTo (mi, 0);
255 // Hack around System.Reflection as found everywhere else
256 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
257 MemberFilter filter, object criteria)
259 ArrayList members = new ArrayList ();
261 if ((mt & MemberTypes.Method) != 0) {
262 foreach (MethodBuilder mb in method_builders)
263 if (filter (mb, criteria))
267 if ((mt & MemberTypes.Property) != 0) {
268 foreach (PropertyBuilder pb in property_builders)
269 if (filter (pb, criteria))
273 if ((mt & MemberTypes.Event) != 0) {
274 foreach (MyEventBuilder eb in event_builders)
275 if (filter (eb, criteria))
279 if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
280 MemberList parent_mi;
282 parent_mi = TypeContainer.FindMembers (
283 TypeBuilder.BaseType, mt, bf, filter, criteria);
285 members.AddRange (parent_mi);
288 return new MemberList (members);
291 public override MemberCache MemberCache {
298 // Populates the methods in the interface
300 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
302 Type return_type = im.ReturnType.Type;
303 if (return_type == null)
304 return_type = this.ResolveType (im.ReturnType, false, im.Location);
306 Type [] arg_types = im.ParameterTypes (this);
309 if (return_type == null)
312 if (return_type.IsPointer && !UnsafeOK (this))
315 if (arg_types == null)
318 foreach (Type t in arg_types){
323 if (t.IsPointer && !UnsafeOK (this))
330 mb = TypeBuilder.DefineMethod (
331 im.Name, interface_method_attributes,
332 return_type, arg_types);
334 InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
336 if (!RegisterMethod (mb, ip, arg_types)) {
342 // Labelling of parameters is taken care of
343 // during the Emit phase via
344 // MethodCore.LabelParameters method so I am
345 // removing the old code here.
353 // Populates the properties in the interface
355 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
358 MethodBuilder get = null, set = null;
359 ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
363 Type prop_type = ip.Type.Type;
364 Type [] setter_args = new Type [1];
366 if (prop_type == null)
369 if (prop_type.IsPointer && !UnsafeOK (this))
372 setter_args [0] = prop_type;
375 // FIXME: properties are missing the following
376 // flags: hidebysig newslot specialname
378 pb = TypeBuilder.DefineProperty (
379 ip.Name, PropertyAttributes.None,
383 get = TypeBuilder.DefineMethod (
384 "get_" + ip.Name, property_attributes ,
388 // HACK because System.Reflection.Emit is lame
390 Type [] null_types = null;
391 InternalParameters inp = new InternalParameters
392 (null_types, Parameters.EmptyReadOnlyParameters);
394 if (!RegisterMethod (get, inp, null)) {
399 pb.SetGetMethod (get);
403 setter_args [0] = prop_type;
405 set = TypeBuilder.DefineMethod (
406 "set_" + ip.Name, property_attributes,
407 TypeManager.void_type, setter_args);
409 set.DefineParameter (1, ParameterAttributes.None, "value");
410 pb.SetSetMethod (set);
413 // HACK because System.Reflection.Emit is lame
415 Parameter [] parms = new Parameter [1];
416 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
417 InternalParameters ipp = new InternalParameters (
418 this, new Parameters (parms, null, Location.Null));
420 if (!RegisterMethod (set, ipp, setter_args)) {
426 TypeManager.RegisterProperty (pb, get, set);
427 property_builders.Add (pb);
432 // Populates the events in the interface
434 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
437 // FIXME: We need to do this after delegates have been
438 // declared or we declare them recursively.
441 MethodBuilder add = null, remove = null;
442 ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
446 Type event_type = ie.Type.Type;
448 if (event_type == null)
451 if (event_type.IsPointer && !UnsafeOK (this))
454 Type [] parameters = new Type [1];
455 parameters [0] = event_type;
457 eb = new MyEventBuilder (null, TypeBuilder, ie.Name,
458 EventAttributes.None, event_type);
461 // Now define the accessors
463 string add_name = "add_" + ie.Name;
465 add = TypeBuilder.DefineMethod (
466 add_name, property_attributes, null, parameters);
467 add.DefineParameter (1, ParameterAttributes.None, "value");
468 eb.SetAddOnMethod (add);
470 string remove_name = "remove_" + ie.Name;
471 remove = TypeBuilder.DefineMethod (
472 remove_name, property_attributes, null, parameters);
473 remove.DefineParameter (1, ParameterAttributes.None, "value");
474 eb.SetRemoveOnMethod (remove);
476 Parameter [] parms = new Parameter [1];
477 parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
478 InternalParameters ip = new InternalParameters (
479 this, new Parameters (parms, null, Location.Null));
481 if (!RegisterMethod (add, ip, parameters)) {
486 if (!RegisterMethod (remove, ip, parameters)) {
491 TypeManager.RegisterEvent (eb, add, remove);
492 event_builders.Add (eb);
498 // Populates the indexers in the interface
500 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
503 ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
507 Type prop_type = ii.Type.Type;
508 Type [] arg_types = ii.ParameterTypes (this);
509 Type [] value_arg_types;
511 if (prop_type == null)
514 if (prop_type.IsPointer && !UnsafeOK (this))
518 // Sets up the extra invisible `value' argument for setters.
520 if (arg_types != null){
521 int count = arg_types.Length;
522 value_arg_types = new Type [count + 1];
524 arg_types.CopyTo (value_arg_types, 0);
525 value_arg_types [count] = prop_type;
527 foreach (Type t in arg_types){
528 if (t.IsPointer && !UnsafeOK (this))
532 value_arg_types = new Type [1];
534 value_arg_types [1] = prop_type;
537 EmitContext ec = new EmitContext (parent, decl_space, Location, null,
538 null, ModFlags, false);
540 IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
541 if (IndexerName == null)
542 IndexerName = "Item";
544 pb = TypeBuilder.DefineProperty (
545 IndexerName, PropertyAttributes.None,
546 prop_type, arg_types);
548 MethodBuilder set_item = null, get_item = null;
550 Parameter [] p = ii.Parameters.FixedParameters;
552 get_item = TypeBuilder.DefineMethod (
553 "get_" + IndexerName, property_attributes,
554 prop_type, arg_types);
555 pb.SetGetMethod (get_item);
557 // HACK because System.Reflection.Emit is lame
559 InternalParameters ip = new InternalParameters (
560 arg_types, ii.Parameters);
562 if (!RegisterMethod (get_item, ip, arg_types)) {
568 for (int i = 0; i < p.Length; i++)
569 get_item.DefineParameter (
571 p [i].Attributes, p [i].Name);
576 Parameter [] p = ii.Parameters.FixedParameters;
580 pv = new Parameter [p.Length + 1];
582 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
583 Parameters value_params = new Parameters (pv, null, Location.Null);
584 value_params.GetParameterInfo (decl_space);
586 set_item = TypeBuilder.DefineMethod (
587 "set_" + IndexerName, property_attributes,
588 TypeManager.void_type, value_arg_types);
589 pb.SetSetMethod (set_item);
591 // HACK because System.Reflection.Emit is lame
593 InternalParameters ip = new InternalParameters (
594 value_arg_types, value_params);
595 if (!RegisterMethod (set_item, ip, value_arg_types)) {
601 for (; i < p.Length; i++)
602 set_item.DefineParameter (
604 p [i].Attributes, p [i].Name);
607 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
610 property_builders.Add (pb);
616 /// Performs the semantic analysis for all the interface members
617 /// that were declared
619 bool SemanticAnalysis ()
621 Hashtable methods = new Hashtable ();
624 if (defined_method != null){
625 foreach (InterfaceMethod im in defined_method){
626 string sig = im.GetSignature (this);
629 // If there was an undefined Type on the signatures
634 if (methods [sig] != null){
642 // FIXME: Here I should check i
647 TypeExpr GetInterfaceTypeByName (Expression name)
649 TypeExpr resolved = ResolveTypeExpr (name, false, Location);
650 if (resolved == null)
653 if (resolved.IsInterface)
658 if (resolved.IsValueType)
659 cause = "is a struct";
660 else if (resolved.IsClass)
661 cause = "is a class";
663 cause = "Should not happen.";
665 Report.Error (527, Location, "`"+resolved.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 TypeExpr [] GetInterfaceBases (out bool error)
686 tbases = new TypeExpr [Bases.Count];
689 foreach (Expression name in Bases){
692 t = GetInterfaceTypeByName (name);
698 if (!t.AsAccessible (Parent, ModFlags))
699 Report.Error (61, Location,
700 "Inconsistent accessibility: base interface `" +
701 t.Name + "' is less accessible than interface `" +
707 return TypeManager.ExpandInterfaces (tbases);
712 // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
716 // Rework the way we recurse, because for recursive
717 // definitions of interfaces (A:B and B:A) we report the
718 // error twice, rather than once.
720 public override TypeBuilder DefineType ()
725 if (TypeBuilder != null)
733 EmitContext ec = new EmitContext (this, this, Location, null, null,
736 ifaces = GetInterfaceBases (out error);
742 foreach (TypeParameter type_param in TypeParameters)
743 if (!type_param.Resolve (this)) {
750 if (TypeManager.NamespaceClash (Name, Location))
753 ModuleBuilder builder = CodeGen.ModuleBuilder;
755 TypeBuilder = builder.DefineType (
758 (Type)null, // Parent Type
760 RootContext.RegisterOrder (this);
762 TypeBuilder builder = Parent.TypeBuilder;
764 TypeBuilder = builder.DefineNestedType (
767 (Type) null, //parent type
770 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
771 tc.RegisterOrder (this);
775 foreach (TypeParameter type_param in TypeParameters)
776 type_param.Define (TypeBuilder);
778 foreach (TypeParameter type_param in TypeParameters)
779 type_param.DefineType (ec, TypeBuilder);
782 if (ifaces != null) {
783 foreach (TypeExpr iface in ifaces) {
784 Type itype = iface.ResolveType (ec);
785 TypeBuilder.AddInterfaceImplementation (itype);
789 TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
796 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
797 // interface is consistent. Either it is `Item' or it is the name defined by all the
798 // indexers with the `IndexerName' attribute.
800 // Turns out that the IndexerNameAttribute is applied to each indexer,
801 // but it is never emitted, instead a DefaultName attribute is attached
804 void DefineIndexers (TypeContainer parent)
806 string interface_indexer_name = null;
808 foreach (InterfaceIndexer ii in defined_indexer){
810 PopulateIndexer (parent, this, ii);
812 if (interface_indexer_name == null){
813 interface_indexer_name = IndexerName;
817 if (IndexerName == interface_indexer_name)
821 668, "Two indexers have different names, " +
822 " you should use the same name for all your indexers");
824 if (interface_indexer_name == null)
825 interface_indexer_name = "Item";
826 IndexerName = interface_indexer_name;
830 /// Performs semantic analysis, and then generates the IL interfaces
832 public override bool DefineMembers (TypeContainer parent)
837 if (!SemanticAnalysis ())
841 if (defined_method != null){
842 foreach (InterfaceMethod im in defined_method)
843 PopulateMethod (parent, this, im);
846 if (defined_properties != null){
847 foreach (InterfaceProperty ip in defined_properties)
848 PopulateProperty (parent, this, ip);
851 if (defined_events != null)
852 foreach (InterfaceEvent ie in defined_events)
853 PopulateEvent (parent, this, ie);
855 if (defined_indexer != null) {
856 DefineIndexers (parent);
858 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
859 parent, IndexerName, ModFlags, Location);
861 TypeBuilder.SetCustomAttribute (cb);
865 if (TypeBuilder.BaseType != null)
866 parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
868 member_cache = new MemberCache (this);
870 members_defined = true;
876 // In the case of Interfaces, there is nothing to do here
878 public override bool Define (TypeContainer parent)
884 /// Applies all the attributes.
886 public void Emit (TypeContainer tc)
888 if (OptAttributes != null) {
889 EmitContext ec = new EmitContext (tc, this, Location, null, null,
891 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
894 // Now emit attributes for each interface member
895 if (defined_method != null) {
896 foreach (InterfaceMethod im in defined_method) {
897 EmitContext ec = new EmitContext (tc, this, Location, null,
898 im.ReturnType.Type, ModFlags, false);
900 MethodCore.LabelParameters (ec, im.Builder,
905 if (im.OptAttributes != null)
906 Attribute.ApplyAttributes (ec, im.Builder,
907 im, im.OptAttributes);
912 if (defined_properties != null) {
913 foreach (InterfaceProperty ip in defined_properties) {
914 EmitContext ec = new EmitContext (tc, this, Location, null,
915 null, ModFlags, false);
917 if (ip.OptAttributes != null)
918 Attribute.ApplyAttributes (ec, ip.Builder, ip, ip.OptAttributes);
922 if (defined_events != null) {
923 foreach (InterfaceEvent ie in defined_events) {
924 EmitContext ec = new EmitContext (tc, this, Location, null,
925 null, ModFlags, false);
927 if (ie.OptAttributes != null)
928 Attribute.ApplyAttributes (ec, ie.Builder, ie, ie.OptAttributes);
933 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
938 EmitContext ec = new EmitContext (parent, loc, null, null, flags);
940 Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
941 ".ctor", MemberTypes.Constructor,
942 BindingFlags.Public | BindingFlags.Instance,
945 if (!(ml is MethodGroupExpr)) {
946 Console.WriteLine ("Internal error !!!!");
950 MethodGroupExpr mg = (MethodGroupExpr) ml;
952 MethodBase constructor = mg.Methods [0];
954 string [] vals = { name };
956 CustomAttributeBuilder cb = null;
958 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
960 Report.Warning (-100, "Can not set the indexer default member attribute");
970 string IMemberContainer.Name {
976 Type IMemberContainer.Type {
982 IMemberContainer IMemberContainer.Parent {
984 return parent_container;
988 MemberCache IMemberContainer.MemberCache {
994 bool IMemberContainer.IsInterface {
1000 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
1002 // Interfaces only contain instance members.
1003 if ((bf & BindingFlags.Instance) == 0)
1004 return MemberList.Empty;
1005 if ((bf & BindingFlags.Public) == 0)
1006 return MemberList.Empty;
1008 ArrayList members = new ArrayList ();
1010 if ((mt & MemberTypes.Method) != 0)
1011 members.AddRange (method_builders);
1013 if ((mt & MemberTypes.Property) != 0)
1014 members.AddRange (property_builders);
1016 if ((mt & MemberTypes.Event) != 0)
1017 members.AddRange (event_builders);
1019 return new MemberList (members);
1023 public class InterfaceMemberBase {
1024 public readonly string Name;
1025 public readonly bool IsNew;
1026 public Attributes OptAttributes;
1028 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
1032 OptAttributes = attrs;
1036 public class InterfaceProperty : InterfaceMemberBase {
1037 public readonly bool HasSet;
1038 public readonly bool HasGet;
1039 public readonly Location Location;
1040 public Expression Type;
1041 public PropertyBuilder Builder;
1043 public InterfaceProperty (Expression type, string name,
1044 bool is_new, bool has_get, bool has_set,
1045 Attributes attrs, Location loc)
1046 : base (name, is_new, attrs)
1055 public class InterfaceEvent : InterfaceMemberBase {
1056 public readonly Location Location;
1057 public Expression Type;
1058 public MyEventBuilder Builder;
1060 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
1062 : base (name, is_new, attrs)
1069 public class InterfaceMethod : InterfaceMemberBase {
1070 public Expression ReturnType;
1071 public readonly Parameters Parameters;
1072 public readonly Location Location;
1073 public MethodBuilder Builder;
1075 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
1076 Attributes attrs, Location l)
1077 : base (name, is_new, attrs)
1079 this.ReturnType = return_type;
1080 this.Parameters = args;
1085 /// Returns the signature for this interface method
1087 public string GetSignature (DeclSpace ds)
1089 ReturnType = ds.ResolveTypeExpr (ReturnType, false, Location);
1090 if (ReturnType == null)
1093 Type ret = ReturnType.Type;
1094 string args = Parameters.GetSignature (ds);
1096 if ((ret == null) || (args == null))
1099 return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
1102 public Type [] ParameterTypes (DeclSpace ds)
1104 return Parameters.GetParameterInfo (ds);
1108 public class InterfaceIndexer : InterfaceMemberBase {
1109 public readonly bool HasGet, HasSet;
1110 public readonly Parameters Parameters;
1111 public readonly Location Location;
1112 public Expression Type;
1113 public PropertyBuilder Builder;
1115 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
1116 bool is_new, Attributes attrs, Location loc)
1117 : base ("", is_new, attrs)
1126 public Type [] ParameterTypes (DeclSpace ds)
1128 return Parameters.GetParameterInfo (ds);