**** Merged r36762 from MCS ****
[mono.git] / mcs / gmcs / decl.cs
1 //
2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 // TODO: Move the method verification stuff from the class.cs and interface.cs here
12 //
13
14 using System;
15 using System.Text;
16 using System.Collections;
17 using System.Globalization;
18 using System.Reflection.Emit;
19 using System.Reflection;
20
21 namespace Mono.CSharp {
22
23         public class MemberName {
24                 public string Name;
25                 public readonly TypeArguments TypeArguments;
26
27                 public readonly MemberName Left;
28
29                 public static readonly MemberName Null = new MemberName ("");
30
31                 public MemberName (string name)
32                 {
33                         this.Name = name;
34                 }
35
36                 public MemberName (string name, TypeArguments args)
37                         : this (name)
38                 {
39                         this.TypeArguments = args;
40                 }
41
42                 public MemberName (MemberName left, string name, TypeArguments args)
43                         : this (name, args)
44                 {
45                         this.Left = left;
46                 }
47
48                 public MemberName (MemberName left, MemberName right)
49                         : this (left, right.Name, right.TypeArguments)
50                 {
51                 }
52
53                 public string GetName ()
54                 {
55                         if (Left != null)
56                                 return Left.GetName () + "." + Name;
57                         else
58                                 return Name;
59                 }
60
61                 public bool IsGeneric {
62                         get {
63                                 if (TypeArguments != null)
64                                         return true;
65                                 else if (Left != null)
66                                         return Left.IsGeneric;
67                                 else
68                                         return false;
69                         }
70                 }
71
72                 public string GetName (bool is_generic)
73                 {
74                         string name = is_generic ? Basename : Name;
75                         if (Left != null)
76                                 return Left.GetName (is_generic) + "." + name;
77                         else
78                                 return name;
79                 }
80
81                 public int CountTypeArguments {
82                         get {
83                                 if (TypeArguments == null)
84                                         return 0;
85                                 else
86                                         return TypeArguments.Count;
87                         }
88                 }
89
90                 public string GetMethodName ()
91                 {
92                         if (Left != null)
93                                 return Left.GetTypeName () + "." + Name;
94                         else
95                                 return Name;
96                 }
97
98                 public static string MakeName (string name, TypeArguments args)
99                 {
100                         if (args == null)
101                                 return name;
102                         else
103                                 return name + "`" + args.Count;
104                 }
105
106                 public static string MakeName (string name, int count)
107                 {
108                         return name + "`" + count;
109                 }
110
111                 public string GetTypeName ()
112                 {
113                         string suffix = "";
114                         if (Left != null)
115                                 return Left.GetTypeName () + "." +
116                                         MakeName (Name, TypeArguments);
117                         else
118                                 return MakeName (Name, TypeArguments);
119                 }
120
121                 protected bool IsUnbound {
122                         get {
123                                 if ((Left != null) && Left.IsUnbound)
124                                         return true;
125                                 else if (TypeArguments == null)
126                                         return false;
127                                 else
128                                         return TypeArguments.IsUnbound;
129                         }
130                 }
131
132                 protected bool CheckUnbound (Location loc)
133                 {
134                         if ((Left != null) && !Left.CheckUnbound (loc))
135                                 return false;
136                         if ((TypeArguments != null) && !TypeArguments.IsUnbound) {
137                                 Report.Error (1031, loc, "Type expected");
138                                 return false;
139                         }
140
141                         return true;
142                 }
143
144                 public Expression GetTypeExpression (Location loc)
145                 {
146                         if (IsUnbound) {
147                                 if (!CheckUnbound (loc))
148                                         return null;
149
150                                 return new UnboundTypeExpression (GetTypeName ());
151                         }
152
153                         if (Left != null) {
154                                 Expression lexpr = Left.GetTypeExpression (loc);
155
156                                 return new MemberAccess (lexpr, Name, TypeArguments, loc);
157                         } else {
158                                 if (TypeArguments != null)
159                                         return new ConstructedType (Name, TypeArguments, loc);
160                                 else
161                                         return new SimpleName (Name, loc);
162                         }
163                 }
164
165                 public MemberName Clone ()
166                 {
167                         if (Left != null)
168                                 return new MemberName (Left.Clone (), Name, TypeArguments);
169                         else
170                                 return new MemberName (Name, TypeArguments);
171                 }
172
173                 public string Basename {
174                         get {
175                                 if (TypeArguments != null)
176                                         return MakeName (Name, TypeArguments);
177                                 else
178                                         return Name;
179                         }
180                 }
181
182                 public override string ToString ()
183                 {
184                         throw new Exception ("This exception is thrown because someone is miss-using\n" +
185                                              "MemberName.ToString in the compiler.  Please report this bug");
186
187                         string full_name;
188                         if (TypeArguments != null)
189                                 full_name = Name + "<" + TypeArguments + ">";
190                         else
191                                 full_name = Name;
192
193                         if (Left != null)
194                                 return Left + "." + full_name;
195                         else
196                                 return full_name;
197                 }
198         }
199
200         /// <summary>
201         ///   Base representation for members.  This is used to keep track
202         ///   of Name, Location and Modifier flags, and handling Attributes.
203         /// </summary>
204         public abstract class MemberCore : Attributable {
205                 /// <summary>
206                 ///   Public name
207                 /// </summary>
208                 public string Name {
209                         get {
210                                 return MemberName.GetName (!(this is GenericMethod) && !(this is Method));
211                         }
212                 }
213
214                 // Is not readonly because of IndexerName attribute
215                 public MemberName MemberName;
216
217                 /// <summary>
218                 ///   Modifier flags that the user specified in the source code
219                 /// </summary>
220                 public int ModFlags;
221
222                 public readonly TypeContainer Parent;
223
224                 /// <summary>
225                 ///   Location where this declaration happens
226                 /// </summary>
227                 public readonly Location Location;
228
229                 [Flags]
230                 public enum Flags {
231                         Obsolete_Undetected = 1,                // Obsolete attribute has not been detected yet
232                         Obsolete = 1 << 1,                      // Type has obsolete attribute
233                         ClsCompliance_Undetected = 1 << 2,      // CLS Compliance has not been detected yet
234                         ClsCompliant = 1 << 3,                  // Type is CLS Compliant
235                         CloseTypeCreated = 1 << 4,              // Tracks whether we have Closed the type
236                         HasCompliantAttribute_Undetected = 1 << 5,      // Presence of CLSCompliantAttribute has not been detected
237                         HasClsCompliantAttribute = 1 << 6,                      // Type has CLSCompliantAttribute
238                         ClsCompliantAttributeTrue = 1 << 7,                     // Type has CLSCompliant (true)
239                         Excluded_Undetected = 1 << 8,           // Conditional attribute has not been detected yet
240                         Excluded = 1 << 9,                                      // Method is conditional
241                         TestMethodDuplication = 1 << 10         // Test for duplication must be performed
242                 }
243   
244                 /// <summary>
245                 ///   MemberCore flags at first detected then cached
246                 /// </summary>
247                 internal Flags caching_flags;
248
249                 public MemberCore (TypeContainer parent, MemberName name, Attributes attrs,
250                                    Location loc)
251                         : base (attrs)
252                 {
253                         Parent = parent;
254                         MemberName = name;
255                         Location = loc;
256                         caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected;
257                 }
258
259                 /// <summary>
260                 /// Tests presence of ObsoleteAttribute and report proper error
261                 /// </summary>
262                 protected void CheckUsageOfObsoleteAttribute (Type type)
263                 {
264                         if (type == null)
265                                 return;
266
267                         ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type);
268                         if (obsolete_attr == null)
269                                 return;
270
271                         AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, Location);
272                 }
273
274                 public abstract bool Define ();
275
276                 // 
277                 // Returns full member name for error message
278                 //
279                 public virtual string GetSignatureForError ()
280                 {
281                         return Name;
282                 }
283
284                 /// <summary>
285                 /// Use this method when MethodBuilder is null
286                 /// </summary>
287                 public virtual string GetSignatureForError (TypeContainer tc)
288                 {
289                         return Name;
290                 }
291
292                 /// <summary>
293                 /// Base Emit method. This is also entry point for CLS-Compliant verification.
294                 /// </summary>
295                 public virtual void Emit ()
296                 {
297                         VerifyObsoleteAttribute ();
298
299                         if (!RootContext.VerifyClsCompliance)
300                                 return;
301
302                         VerifyClsCompliance (Parent);
303                 }
304
305                 public bool InUnsafe {
306                         get {
307                                 return ((ModFlags & Modifiers.UNSAFE) != 0) || Parent.UnsafeContext;
308                         }
309                 }
310
311                 // 
312                 // Whehter is it ok to use an unsafe pointer in this type container
313                 //
314                 public bool UnsafeOK (DeclSpace parent)
315                 {
316                         //
317                         // First check if this MemberCore modifier flags has unsafe set
318                         //
319                         if ((ModFlags & Modifiers.UNSAFE) != 0)
320                                 return true;
321
322                         if (parent.UnsafeContext)
323                                 return true;
324
325                         Expression.UnsafeError (Location);
326                         return false;
327                 }
328
329                 /// <summary>
330                 /// Returns instance of ObsoleteAttribute for this MemberCore
331                 /// </summary>
332                 public ObsoleteAttribute GetObsoleteAttribute (DeclSpace ds)
333                 {
334                         // ((flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0) is slower, but why ?
335                         if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) {
336                                 return null;
337                         }
338
339                         caching_flags &= ~Flags.Obsolete_Undetected;
340
341                         if (OptAttributes == null)
342                                 return null;
343
344                         Attribute obsolete_attr = OptAttributes.Search (
345                                 TypeManager.obsolete_attribute_type, ds.EmitContext);
346                         if (obsolete_attr == null)
347                                 return null;
348
349                         ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ds);
350                         if (obsolete == null)
351                                 return null;
352
353                         caching_flags |= Flags.Obsolete;
354                         return obsolete;
355                 }
356
357                 /// <summary>
358                 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
359                 /// </summary>
360                 public override bool IsClsCompliaceRequired (DeclSpace container)
361                 {
362                         if ((caching_flags & Flags.ClsCompliance_Undetected) == 0)
363                                 return (caching_flags & Flags.ClsCompliant) != 0;
364
365                         if (GetClsCompliantAttributeValue (container) && IsExposedFromAssembly (container)) {
366                                 caching_flags &= ~Flags.ClsCompliance_Undetected;
367                                 caching_flags |= Flags.ClsCompliant;
368                                 return true;
369                         }
370
371                         caching_flags &= ~Flags.ClsCompliance_Undetected;
372                         return false;
373                 }
374
375                 /// <summary>
376                 /// Returns true when MemberCore is exposed from assembly.
377                 /// </summary>
378                 protected bool IsExposedFromAssembly (DeclSpace ds)
379                 {
380                         if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
381                                 return false;
382                         
383                         DeclSpace parentContainer = ds;
384                         while (parentContainer != null && parentContainer.ModFlags != 0) {
385                                 if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
386                                         return false;
387                                 parentContainer = parentContainer.Parent;
388                         }
389                         return true;
390                 }
391
392                 /// <summary>
393                 /// Resolve CLSCompliantAttribute value or gets cached value.
394                 /// </summary>
395                 bool GetClsCompliantAttributeValue (DeclSpace ds)
396                 {
397                         if (OptAttributes != null) {
398                                 Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ds.EmitContext);
399                                 if (cls_attribute != null) {
400                                         caching_flags |= Flags.HasClsCompliantAttribute;
401                                         return cls_attribute.GetClsCompliantAttributeValue (ds);
402                                 }
403                         }
404                         return ds.GetClsCompliantAttributeValue ();
405                 }
406
407                 /// <summary>
408                 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
409                 /// </summary>
410                 protected bool HasClsCompliantAttribute {
411                         get {
412                                 return (caching_flags & Flags.HasClsCompliantAttribute) != 0;
413                         }
414                 }
415
416                 /// <summary>
417                 /// The main virtual method for CLS-Compliant verifications.
418                 /// The method returns true if member is CLS-Compliant and false if member is not
419                 /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
420                 /// and add their extra verifications.
421                 /// </summary>
422                 protected virtual bool VerifyClsCompliance (DeclSpace ds)
423                 {
424                         if (!IsClsCompliaceRequired (ds)) {
425                                 if ((RootContext.WarningLevel >= 2) && HasClsCompliantAttribute && !IsExposedFromAssembly (ds)) {
426                                         Report.Warning (3019, Location, "CLS compliance checking will not be performed on '{0}' because it is private or internal", GetSignatureForError ());
427                                 }
428                                 return false;
429                         }
430
431                         if (!CodeGen.Assembly.IsClsCompliant) {
432                                 if (HasClsCompliantAttribute) {
433                                         Report.Error (3014, Location, "'{0}' cannot be marked as CLS-compliant because the assembly does not have a CLSCompliant attribute", GetSignatureForError ());
434                                 }
435                                 return false;
436                         }
437
438                         int index = Name.LastIndexOf ('.');
439                         if (Name [index > 0 ? index + 1 : 0] == '_') {
440                                 Report.Error (3008, Location, "Identifier '{0}' is not CLS-compliant", GetSignatureForError () );
441                         }
442                         return true;
443                 }
444
445                 protected abstract void VerifyObsoleteAttribute ();
446
447         }
448
449         /// <summary>
450         ///   Base class for structs, classes, enumerations and interfaces.  
451         /// </summary>
452         /// <remarks>
453         ///   They all create new declaration spaces.  This
454         ///   provides the common foundation for managing those name
455         ///   spaces.
456         /// </remarks>
457         public abstract class DeclSpace : MemberCore, IAlias {
458                 /// <summary>
459                 ///   This points to the actual definition that is being
460                 ///   created with System.Reflection.Emit
461                 /// </summary>
462                 public TypeBuilder TypeBuilder;
463
464                 /// <summary>
465                 ///   If we are a generic type, this is the type we are
466                 ///   currently defining.  We need to lookup members on this
467                 ///   instead of the TypeBuilder.
468                 /// </summary>
469                 public Type CurrentType;
470
471                 //
472                 // This is the namespace in which this typecontainer
473                 // was declared.  We use this to resolve names.
474                 //
475                 public NamespaceEntry NamespaceEntry;
476
477                 public Hashtable Cache = new Hashtable ();
478                 
479                 public string Basename;
480                 
481                 protected Hashtable defined_names;
482
483                 readonly bool is_generic;
484                 readonly int count_type_params;
485
486                 // The emit context for toplevel objects.
487                 protected EmitContext ec;
488                 
489                 public EmitContext EmitContext {
490                         get { return ec; }
491                 }
492
493                 //
494                 // Whether we are Generic
495                 //
496                 public bool IsGeneric {
497                         get {
498                                 if (is_generic)
499                                         return true;
500                                 else if (Parent != null)
501                                         return Parent.IsGeneric;
502                                 else
503                                         return false;
504                         }
505                 }
506
507                 static string[] attribute_targets = new string [] { "type" };
508
509                 public DeclSpace (NamespaceEntry ns, TypeContainer parent, MemberName name,
510                                   Attributes attrs, Location l)
511                         : base (parent, name, attrs, l)
512                 {
513                         NamespaceEntry = ns;
514                         Basename = name.Name;
515                         defined_names = new Hashtable ();
516                         if (name.TypeArguments != null) {
517                                 is_generic = true;
518                                 count_type_params = name.TypeArguments.Count;
519                         }
520                         if (parent != null)
521                                 count_type_params += parent.count_type_params;
522                 }
523
524                 /// <summary>
525                 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
526                 /// </summary>
527                 protected bool AddToContainer (MemberCore symbol, bool is_method, string fullname, string basename)
528                 {
529                         if (basename == Basename && !(this is Interface)) {
530                                 Report.SymbolRelatedToPreviousError (this);
531                                 Report.Error (542, "'{0}': member names cannot be the same as their enclosing type", symbol.Location, symbol.GetSignatureForError ());
532                                 return false;
533                         }
534
535                         MemberCore mc = (MemberCore)defined_names [fullname];
536
537                         if (is_method && (mc is MethodCore || mc is IMethodData)) {
538                                 symbol.caching_flags |= Flags.TestMethodDuplication;
539                                 mc.caching_flags |= Flags.TestMethodDuplication;
540                                 return true;
541                         }
542
543                         if (mc != null) {
544                                 Report.SymbolRelatedToPreviousError (mc);
545                                 Report.Error (102, symbol.Location, "The type '{0}' already contains a definition for '{1}'", GetSignatureForError (), basename);
546                                 return false;
547                         }
548
549                         defined_names.Add (fullname, symbol);
550                         return true;
551                 }
552
553                 public void RecordDecl ()
554                 {
555                         if ((NamespaceEntry != null) && (Parent == RootContext.Tree.Types))
556                                 NamespaceEntry.DefineName (MemberName.Basename, this);
557                 }
558
559                 /// <summary>
560                 ///   Returns the MemberCore associated with a given name in the declaration
561                 ///   space. It doesn't return method based symbols !!
562                 /// </summary>
563                 /// 
564                 public MemberCore GetDefinition (string name)
565                 {
566                         return (MemberCore)defined_names [name];
567                 }
568
569                 bool in_transit = false;
570                 
571                 /// <summary>
572                 ///   This function is used to catch recursive definitions
573                 ///   in declarations.
574                 /// </summary>
575                 public bool InTransit {
576                         get {
577                                 return in_transit;
578                         }
579
580                         set {
581                                 in_transit = value;
582                         }
583                 }
584
585                 /// <summary>
586                 ///   Looks up the alias for the name
587                 /// </summary>
588                 public IAlias LookupAlias (string name)
589                 {
590                         if (NamespaceEntry != null)
591                                 return NamespaceEntry.LookupAlias (name);
592                         else
593                                 return null;
594                 }
595                 
596                 // 
597                 // root_types contains all the types.  All TopLevel types
598                 // hence have a parent that points to `root_types', that is
599                 // why there is a non-obvious test down here.
600                 //
601                 public bool IsTopLevel {
602                         get {
603                                 if (Parent != null){
604                                         if (Parent.Parent == null)
605                                                 return true;
606                                 }
607                                 return false;
608                         }
609                 }
610
611                 public virtual void CloseType ()
612                 {
613                         if ((caching_flags & Flags.CloseTypeCreated) == 0){
614                                 try {
615                                         TypeBuilder.CreateType ();
616                                 } catch {
617                                         //
618                                         // The try/catch is needed because
619                                         // nested enumerations fail to load when they
620                                         // are defined.
621                                         //
622                                         // Even if this is the right order (enumerations
623                                         // declared after types).
624                                         //
625                                         // Note that this still creates the type and
626                                         // it is possible to save it
627                                 }
628                                 caching_flags |= Flags.CloseTypeCreated;
629                         }
630                 }
631
632                 /// <remarks>
633                 ///  Should be overriten by the appropriate declaration space
634                 /// </remarks>
635                 public abstract TypeBuilder DefineType ();
636                 
637                 /// <summary>
638                 ///   Define all members, but don't apply any attributes or do anything which may
639                 ///   access not-yet-defined classes.  This method also creates the MemberCache.
640                 /// </summary>
641                 public abstract bool DefineMembers (TypeContainer parent);
642
643                 //
644                 // Whether this is an `unsafe context'
645                 //
646                 public bool UnsafeContext {
647                         get {
648                                 if ((ModFlags & Modifiers.UNSAFE) != 0)
649                                         return true;
650                                 if (Parent != null)
651                                         return Parent.UnsafeContext;
652                                 return false;
653                         }
654                 }
655
656                 public static string MakeFQN (string nsn, string name)
657                 {
658                         if (nsn == "")
659                                 return name;
660                         return String.Concat (nsn, ".", name);
661                 }
662
663                 EmitContext type_resolve_ec;
664                 EmitContext GetTypeResolveEmitContext (TypeContainer parent, Location loc)
665                 {
666                         type_resolve_ec = new EmitContext (parent, this, loc, null, null, ModFlags, false);
667                         type_resolve_ec.ResolvingTypeTree = true;
668
669                         return type_resolve_ec;
670                 }
671
672                 public Type ResolveNestedType (Type t, Location loc)
673                 {
674                         TypeContainer tc = TypeManager.LookupTypeContainer (t);
675                         if ((tc != null) && tc.IsGeneric) {
676                                 if (!IsGeneric) {
677                                         int tnum = TypeManager.GetNumberOfTypeArguments (t);
678                                         Report.Error (305, loc,
679                                                       "Using the generic type `{0}' " +
680                                                       "requires {1} type arguments",
681                                                       TypeManager.GetFullName (t), tnum);
682                                         return null;
683                                 }
684
685                                 TypeParameter[] args;
686                                 if (this is GenericMethod)
687                                         args = Parent.TypeParameters;
688                                 else
689                                         args = TypeParameters;
690
691                                 TypeExpr ctype = new ConstructedType (t, args, loc);
692                                 ctype = ctype.ResolveAsTypeTerminal (ec);
693                                 if (ctype == null)
694                                         return null;
695
696                                 t = ctype.Type;
697                         }
698
699                         return t;
700                 }
701
702                 // <summary>
703                 //    Resolves the expression `e' for a type, and will recursively define
704                 //    types.  This should only be used for resolving base types.
705                 // </summary>
706                 public TypeExpr ResolveTypeExpr (Expression e, Location loc)
707                 {
708                         if (type_resolve_ec == null)
709                                 type_resolve_ec = GetTypeResolveEmitContext (Parent, loc);
710                         type_resolve_ec.loc = loc;
711                         if (this is GenericMethod)
712                                 type_resolve_ec.ContainerType = Parent.TypeBuilder;
713                         else
714                                 type_resolve_ec.ContainerType = TypeBuilder;
715
716                         return e.ResolveAsTypeTerminal (type_resolve_ec);
717                 }
718                 
719                 public bool CheckAccessLevel (Type check_type) 
720                 {
721                         TypeBuilder tb;
722                         if ((this is GenericMethod) || (this is Iterator))
723                                 tb = Parent.TypeBuilder;
724                         else
725                                 tb = TypeBuilder;
726
727                         if (check_type.IsGenericInstance)
728                                 check_type = check_type.GetGenericTypeDefinition ();
729
730                         if (check_type == tb)
731                                 return true;
732
733                         if (check_type.IsGenericParameter)
734                                 return true; // FIXME
735                         
736                         TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
737                         
738                         //
739                         // Broken Microsoft runtime, return public for arrays, no matter what 
740                         // the accessibility is for their underlying class, and they return 
741                         // NonPublic visibility for pointers
742                         //
743                         if (check_type.IsArray || check_type.IsPointer)
744                                 return CheckAccessLevel (TypeManager.GetElementType (check_type));
745
746                         switch (check_attr){
747                         case TypeAttributes.Public:
748                                 return true;
749
750                         case TypeAttributes.NotPublic:
751
752                                 if (TypeBuilder == null)
753                                         // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
754                                         //        However, this is invoked again later -- so safe to return true.
755                                         //        May also be null when resolving top-level attributes.
756                                         return true;
757                                 //
758                                 // This test should probably use the declaringtype.
759                                 //
760                                 return check_type.Assembly == TypeBuilder.Assembly;
761
762                         case TypeAttributes.NestedPublic:
763                                 return true;
764
765                         case TypeAttributes.NestedPrivate:
766                                 return NestedAccessible (tb, check_type);
767
768                         case TypeAttributes.NestedFamily:
769                                 //
770                                 // Only accessible to methods in current type or any subtypes
771                                 //
772                                 return FamilyAccessible (tb, check_type);
773
774                         case TypeAttributes.NestedFamANDAssem:
775                                 return (check_type.Assembly == tb.Assembly) &&
776                                         FamilyAccessible (tb, check_type);
777
778                         case TypeAttributes.NestedFamORAssem:
779                                 return (check_type.Assembly == tb.Assembly) ||
780                                         FamilyAccessible (tb, check_type);
781
782                         case TypeAttributes.NestedAssembly:
783                                 return check_type.Assembly == tb.Assembly;
784                         }
785
786                         Console.WriteLine ("HERE: " + check_attr);
787                         return false;
788
789                 }
790
791                 protected bool NestedAccessible (Type tb, Type check_type)
792                 {
793                         string check_type_name = check_type.FullName;
794                         
795                         // At this point, we already know check_type is a nested class.
796                         int cio = check_type_name.LastIndexOf ('+');
797                         
798                         // Ensure that the string 'container' has a '+' in it to avoid false matches
799                         string container = check_type_name.Substring (0, cio + 1);
800
801                         // Ensure that type_name ends with a '+' so that it can match 'container', if necessary
802                         string type_name = tb.FullName + "+";
803
804                         // If the current class is nested inside the container of check_type,
805                         // we can access check_type even if it is private or protected.
806                         return type_name.StartsWith (container);
807                 }
808
809                 protected bool FamilyAccessible (Type tb, Type check_type)
810                 {
811                         Type declaring = check_type.DeclaringType;
812                         if (tb == declaring || TypeManager.IsFamilyAccessible (tb, declaring))
813                                 return true;
814
815                         return NestedAccessible (tb, check_type);
816                 }
817
818                 // Access level of a type.
819                 const int X = 1;
820                 enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope'
821                         // Public    Assembly   Protected
822                         Protected           = (0 << 0) | (0 << 1) | (X << 2),
823                         Public              = (X << 0) | (X << 1) | (X << 2),
824                         Private             = (0 << 0) | (0 << 1) | (0 << 2),
825                         Internal            = (0 << 0) | (X << 1) | (0 << 2),
826                         ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2),
827                 }
828
829                 static AccessLevel GetAccessLevelFromModifiers (int flags)
830                 {
831                         if ((flags & Modifiers.INTERNAL) != 0) {
832
833                                 if ((flags & Modifiers.PROTECTED) != 0)
834                                         return AccessLevel.ProtectedOrInternal;
835                                 else
836                                         return AccessLevel.Internal;
837
838                         } else if ((flags & Modifiers.PROTECTED) != 0)
839                                 return AccessLevel.Protected;
840                         else if ((flags & Modifiers.PRIVATE) != 0)
841                                 return AccessLevel.Private;
842                         else
843                                 return AccessLevel.Public;
844                 }
845
846                 // What is the effective access level of this?
847                 // TODO: Cache this?
848                 AccessLevel EffectiveAccessLevel {
849                         get {
850                                 AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags);
851                                 if (!IsTopLevel && (Parent != null))
852                                         return myAccess & Parent.EffectiveAccessLevel;
853                                 return myAccess;
854                         }
855                 }
856
857                 // Return the access level for type `t'
858                 static AccessLevel TypeEffectiveAccessLevel (Type t)
859                 {
860                         if (t.IsPublic)
861                                 return AccessLevel.Public;
862                         if (t.IsNestedPrivate)
863                                 return AccessLevel.Private;
864                         if (t.IsNotPublic)
865                                 return AccessLevel.Internal;
866
867                         // By now, it must be nested
868                         AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType);
869
870                         if (t.IsNestedPublic)
871                                 return parentLevel;
872                         if (t.IsNestedAssembly)
873                                 return parentLevel & AccessLevel.Internal;
874                         if (t.IsNestedFamily)
875                                 return parentLevel & AccessLevel.Protected;
876                         if (t.IsNestedFamORAssem)
877                                 return parentLevel & AccessLevel.ProtectedOrInternal;
878                         if (t.IsNestedFamANDAssem)
879                                 throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
880
881                         // nested private is taken care of
882
883                         throw new Exception ("I give up, what are you?");
884                 }
885
886                 //
887                 // This answers `is the type P, as accessible as a member M which has the
888                 // accessability @flags which is declared as a nested member of the type T, this declspace'
889                 //
890                 public bool AsAccessible (Type p, int flags)
891                 {
892                         if (p.IsGenericParameter)
893                                 return true; // FIXME
894
895                         //
896                         // 1) if M is private, its accessability is the same as this declspace.
897                         // we already know that P is accessible to T before this method, so we
898                         // may return true.
899                         //
900
901                         if ((flags & Modifiers.PRIVATE) != 0)
902                                 return true;
903
904                         while (p.IsArray || p.IsPointer || p.IsByRef)
905                                 p = TypeManager.GetElementType (p);
906
907                         AccessLevel pAccess = TypeEffectiveAccessLevel (p);
908                         AccessLevel mAccess = this.EffectiveAccessLevel &
909                                 GetAccessLevelFromModifiers (flags);
910
911                         // for every place from which we can access M, we must
912                         // be able to access P as well. So, we want
913                         // For every bit in M and P, M_i -> P_1 == true
914                         // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0
915
916                         return ~ (~ mAccess | pAccess) == 0;
917                 }
918                 
919                 static DoubleHash dh = new DoubleHash (1000);
920
921                 Type DefineTypeAndParents (DeclSpace tc)
922                 {
923                         DeclSpace container = tc.Parent;
924
925                         if (container.TypeBuilder == null && container.Name != "")
926                                 DefineTypeAndParents (container);
927
928                         return tc.DefineType ();
929                 }
930                 
931                 Type LookupInterfaceOrClass (string ns, string name, out bool error)
932                 {
933                         DeclSpace parent;
934                         Type t;
935                         object r;
936                         
937                         error = false;
938
939                         if (dh.Lookup (ns, name, out r))
940                                 return (Type) r;
941                         else {
942                                 if (ns != ""){
943                                         if (Namespace.IsNamespace (ns)){
944                                                 string fullname = (ns != "") ? ns + "." + name : name;
945                                                 t = TypeManager.LookupType (fullname);
946                                         } else
947                                                 t = null;
948                                 } else
949                                         t = TypeManager.LookupType (name);
950                         }
951                         
952                         if (t != null) {
953                                 dh.Insert (ns, name, t);
954                                 return t;
955                         }
956
957                         //
958                         // In case we are fed a composite name, normalize it.
959                         //
960                         int p = name.LastIndexOf ('.');
961                         if (p != -1){
962                                 ns = MakeFQN (ns, name.Substring (0, p));
963                                 name = name.Substring (p+1);
964                         }
965                         
966                         parent = RootContext.Tree.LookupByNamespace (ns, name);
967                         if (parent == null) {
968                                 dh.Insert (ns, name, null);
969                                 return null;
970                         }
971
972                         t = DefineTypeAndParents (parent);
973                         if (t == null){
974                                 error = true;
975                                 return null;
976                         }
977                         
978                         dh.Insert (ns, name, t);
979                         return t;
980                 }
981
982                 public static void Error_AmbiguousTypeReference (Location loc, string name, string t1, string t2)
983                 {
984                         Report.Error (104, loc,
985                                       "`{0}' is an ambiguous reference ({1} or {2})",
986                                       name, t1, t2);
987                 }
988
989                 public Type FindNestedType (Location loc, string name,
990                                             out DeclSpace containing_ds)
991                 {
992                         Type t;
993                         bool error;
994
995                         containing_ds = this;
996                         while (containing_ds != null){
997                                 Type container_type = containing_ds.TypeBuilder;
998                                 Type current_type = container_type;
999
1000                                 while (current_type != null && current_type != TypeManager.object_type) {
1001                                         string pre = current_type.FullName;
1002
1003                                         t = LookupInterfaceOrClass (pre, name, out error);
1004                                         if (error)
1005                                                 return null;
1006
1007                                         if ((t != null) && containing_ds.CheckAccessLevel (t))
1008                                                 return t;
1009
1010                                         current_type = current_type.BaseType;
1011                                 }
1012                                 containing_ds = containing_ds.Parent;
1013                         }
1014
1015                         return null;
1016                 }
1017
1018                 /// <summary>
1019                 ///   GetType is used to resolve type names at the DeclSpace level.
1020                 ///   Use this to lookup class/struct bases, interface bases or 
1021                 ///   delegate type references
1022                 /// </summary>
1023                 ///
1024                 /// <remarks>
1025                 ///   Contrast this to LookupType which is used inside method bodies to 
1026                 ///   lookup types that have already been defined.  GetType is used
1027                 ///   during the tree resolution process and potentially define
1028                 ///   recursively the type
1029                 /// </remarks>
1030                 public Type FindType (Location loc, string name)
1031                 {
1032                         Type t;
1033                         bool error;
1034
1035                         //
1036                         // For the case the type we are looking for is nested within this one
1037                         // or is in any base class
1038                         //
1039                         DeclSpace containing_ds = this;
1040
1041                         while (containing_ds != null){
1042                                 Type container_type = containing_ds.TypeBuilder;
1043                                 Type current_type = container_type;
1044
1045                                 while (current_type != null && current_type != TypeManager.object_type) {
1046                                         string pre = current_type.FullName;
1047
1048                                         t = LookupInterfaceOrClass (pre, name, out error);
1049                                         if (error)
1050                                                 return null;
1051
1052                                         if ((t != null) && containing_ds.CheckAccessLevel (t))
1053                                                 return ResolveNestedType (t, loc);
1054
1055                                         current_type = current_type.BaseType;
1056                                 }
1057                                 containing_ds = containing_ds.Parent;
1058                         }
1059
1060                         //
1061                         // Attempt to lookup the class on our namespace and all it's implicit parents
1062                         //
1063                         for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.ImplicitParent) {
1064                                 t = LookupInterfaceOrClass (ns.FullName, name, out error);
1065                                 if (error)
1066                                         return null;
1067
1068                                 if (t != null)
1069                                         return t;
1070                         }
1071                         
1072                         //
1073                         // Attempt to do a direct unqualified lookup
1074                         //
1075                         t = LookupInterfaceOrClass ("", name, out error);
1076                         if (error)
1077                                 return null;
1078                         
1079                         if (t != null)
1080                                 return t;
1081                         
1082                         //
1083                         // Attempt to lookup the class on any of the `using'
1084                         // namespaces
1085                         //
1086
1087                         for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.Parent){
1088
1089                                 t = LookupInterfaceOrClass (ns.FullName, name, out error);
1090                                 if (error)
1091                                         return null;
1092
1093                                 if (t != null)
1094                                         return t;
1095
1096                                 if (name.IndexOf ('.') > 0)
1097                                         continue;
1098
1099                                 IAlias alias_value = ns.LookupAlias (name);
1100                                 if (alias_value != null) {
1101                                         t = LookupInterfaceOrClass ("", alias_value.Name, out error);
1102                                         if (error)
1103                                                 return null;
1104
1105                                         if (t != null)
1106                                                 return t;
1107                                 }
1108
1109                                 //
1110                                 // Now check the using clause list
1111                                 //
1112                                 Type match = null;
1113                                 foreach (Namespace using_ns in ns.GetUsingTable ()) {
1114                                         match = LookupInterfaceOrClass (using_ns.Name, name, out error);
1115                                         if (error)
1116                                                 return null;
1117
1118                                         if (match != null) {
1119                                                 if (t != null){
1120                                                         if (CheckAccessLevel (match)) {
1121                                                                 Error_AmbiguousTypeReference (loc, name, t.FullName, match.FullName);
1122                                                                 return null;
1123                                                         }
1124                                                         continue;
1125                                                 }
1126                                                 
1127                                                 t = match;
1128                                         }
1129                                 }
1130                                 if (t != null)
1131                                         return t;
1132                         }
1133
1134                         //Report.Error (246, Location, "Can not find type `"+name+"'");
1135                         return null;
1136                 }
1137
1138                 /// <remarks>
1139                 ///   This function is broken and not what you're looking for.  It should only
1140                 ///   be used while the type is still being created since it doesn't use the cache
1141                 ///   and relies on the filter doing the member name check.
1142                 /// </remarks>
1143                 public abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1144                                                         MemberFilter filter, object criteria);
1145
1146                 /// <remarks>
1147                 ///   If we have a MemberCache, return it.  This property may return null if the
1148                 ///   class doesn't have a member cache or while it's still being created.
1149                 /// </remarks>
1150                 public abstract MemberCache MemberCache {
1151                         get;
1152                 }
1153
1154                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1155                 {
1156                         try {
1157                                 TypeBuilder.SetCustomAttribute (cb);
1158                         } catch (System.ArgumentException e) {
1159                                 Report.Warning (-21, a.Location,
1160                                                 "The CharSet named property on StructLayout\n"+
1161                                                 "\tdoes not work correctly on Microsoft.NET\n"+
1162                                                 "\tYou might want to remove the CharSet declaration\n"+
1163                                                 "\tor compile using the Mono runtime instead of the\n"+
1164                                                 "\tMicrosoft .NET runtime\n"+
1165                                                 "\tThe runtime gave the error: " + e);
1166                         }
1167                 }
1168
1169                 /// <summary>
1170                 /// Goes through class hierarchy and get value of first CLSCompliantAttribute that found.
1171                 /// If no is attribute exists then return assembly CLSCompliantAttribute.
1172                 /// </summary>
1173                 public bool GetClsCompliantAttributeValue ()
1174                 {
1175                         if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0)
1176                                 return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0;
1177
1178                         caching_flags &= ~Flags.HasCompliantAttribute_Undetected;
1179
1180                         if (OptAttributes != null) {
1181                                 Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ec);
1182                                 if (cls_attribute != null) {
1183                                         caching_flags |= Flags.HasClsCompliantAttribute;
1184                                         if (cls_attribute.GetClsCompliantAttributeValue (this)) {
1185                                                 caching_flags |= Flags.ClsCompliantAttributeTrue;
1186                                                 return true;
1187                                         }
1188                                         return false;
1189                                 }
1190                         }
1191
1192                         if (Parent == null) {
1193                                 if (CodeGen.Assembly.IsClsCompliant) {
1194                                         caching_flags |= Flags.ClsCompliantAttributeTrue;
1195                                         return true;
1196                                 }
1197                                 return false;
1198                         }
1199
1200                         if (Parent.GetClsCompliantAttributeValue ()) {
1201                                 caching_flags |= Flags.ClsCompliantAttributeTrue;
1202                                 return true;
1203                         }
1204                         return false;
1205                 }
1206
1207                 //
1208                 // Extensions for generics
1209                 //
1210                 TypeParameter[] type_params;
1211                 TypeParameter[] type_param_list;
1212
1213                 protected string GetInstantiationName ()
1214                 {
1215                         StringBuilder sb = new StringBuilder (Name);
1216                         sb.Append ("<");
1217                         for (int i = 0; i < type_param_list.Length; i++) {
1218                                 if (i > 0)
1219                                         sb.Append (",");
1220                                 sb.Append (type_param_list [i].Name);
1221                         }
1222                         sb.Append (">");
1223                         return sb.ToString ();
1224                 }
1225
1226                 bool check_type_parameter (ArrayList list, int start, string name)
1227                 {
1228                         for (int i = 0; i < start; i++) {
1229                                 TypeParameter param = (TypeParameter) list [i];
1230
1231                                 if (param.Name != name)
1232                                         continue;
1233
1234                                 if (RootContext.WarningLevel >= 3)
1235                                         Report.Warning (
1236                                                 693, Location,
1237                                                 "Type parameter `{0}' has same name " +
1238                                                 "as type parameter from outer type `{1}'",
1239                                                 name, Parent.GetInstantiationName ());
1240
1241                                 return false;
1242                         }
1243
1244                         return true;
1245                 }
1246
1247                 TypeParameter[] initialize_type_params ()
1248                 {
1249                         if (type_param_list != null)
1250                                 return type_param_list;
1251
1252                         DeclSpace the_parent = Parent;
1253                         if (this is GenericMethod)
1254                                 the_parent = null;
1255
1256                         int start = 0;
1257                         TypeParameter[] parent_params = null;
1258                         if ((the_parent != null) && the_parent.IsGeneric) {
1259                                 parent_params = the_parent.initialize_type_params ();
1260                                 start = parent_params != null ? parent_params.Length : 0;
1261                         }
1262
1263                         ArrayList list = new ArrayList ();
1264                         if (parent_params != null)
1265                                 list.AddRange (parent_params);
1266
1267                         int count = type_params != null ? type_params.Length : 0;
1268                         for (int i = 0; i < count; i++) {
1269                                 TypeParameter param = type_params [i];
1270                                 check_type_parameter (list, start, param.Name);
1271                                 list.Add (param);
1272                         }
1273
1274                         type_param_list = new TypeParameter [list.Count];
1275                         list.CopyTo (type_param_list, 0);
1276                         return type_param_list;
1277                 }
1278
1279                 public void SetParameterInfo (ArrayList constraints_list)
1280                 {
1281                         if (!is_generic) {
1282                                 if (constraints_list != null) {
1283                                         Report.Error (
1284                                                 80, Location, "Contraints are not allowed " +
1285                                                 "on non-generic declarations");
1286                                 }
1287
1288                                 return;
1289                         }
1290
1291                         string[] names = MemberName.TypeArguments.GetDeclarations ();
1292                         type_params = new TypeParameter [names.Length];
1293
1294                         //
1295                         // Register all the names
1296                         //
1297                         for (int i = 0; i < type_params.Length; i++) {
1298                                 string name = names [i];
1299
1300                                 Constraints constraints = null;
1301                                 if (constraints_list != null) {
1302                                         foreach (Constraints constraint in constraints_list) {
1303                                                 if (constraint.TypeParameter == name) {
1304                                                         constraints = constraint;
1305                                                         break;
1306                                                 }
1307                                         }
1308                                 }
1309
1310                                 type_params [i] = new TypeParameter (Parent, name, constraints, Location);
1311
1312                                 string full_name = Name + "." + name;
1313                                 AddToContainer (type_params [i], false, full_name, name);
1314                         }
1315                 }
1316
1317                 public TypeParameter[] TypeParameters {
1318                         get {
1319                                 if (!IsGeneric)
1320                                         throw new InvalidOperationException ();
1321                                 if (type_param_list == null)
1322                                         initialize_type_params ();
1323
1324                                 return type_param_list;
1325                         }
1326                 }
1327
1328                 protected TypeParameter[] CurrentTypeParameters {
1329                         get {
1330                                 if (!IsGeneric)
1331                                         throw new InvalidOperationException ();
1332                                 if (type_params != null)
1333                                         return type_params;
1334                                 else
1335                                         return new TypeParameter [0];
1336                         }
1337                 }
1338
1339                 public int CountTypeParameters {
1340                         get {
1341                                 return count_type_params;
1342                         }
1343                 }
1344
1345                 public TypeParameterExpr LookupGeneric (string name, Location loc)
1346                 {
1347                         if (!IsGeneric)
1348                                 return null;
1349
1350                         foreach (TypeParameter type_param in CurrentTypeParameters) {
1351                                 if (type_param.Name != name)
1352                                         continue;
1353
1354                                 return new TypeParameterExpr (type_param, loc);
1355                         }
1356
1357                         if (Parent != null)
1358                                 return Parent.LookupGeneric (name, loc);
1359
1360                         return null;
1361                 }
1362
1363                 bool IAlias.IsType {
1364                         get { return true; }
1365                 }
1366
1367                 string IAlias.Name {
1368                         get { return Name; }
1369                 }
1370
1371                 TypeExpr IAlias.ResolveAsType (EmitContext ec)
1372                 {
1373                         if (TypeBuilder == null)
1374                                 throw new InvalidOperationException ();
1375
1376                         if (CurrentType != null)
1377                                 return new TypeExpression (CurrentType, Location);
1378                         else
1379                                 return new TypeExpression (TypeBuilder, Location);
1380                 }
1381
1382                 public override string[] ValidAttributeTargets {
1383                         get {
1384                                 return attribute_targets;
1385                         }
1386                 }
1387         }
1388
1389         /// <summary>
1390         ///   This is a readonly list of MemberInfo's.      
1391         /// </summary>
1392         public class MemberList : IList {
1393                 public readonly IList List;
1394                 int count;
1395
1396                 /// <summary>
1397                 ///   Create a new MemberList from the given IList.
1398                 /// </summary>
1399                 public MemberList (IList list)
1400                 {
1401                         if (list != null)
1402                                 this.List = list;
1403                         else
1404                                 this.List = new ArrayList ();
1405                         count = List.Count;
1406                 }
1407
1408                 /// <summary>
1409                 ///   Concatenate the ILists `first' and `second' to a new MemberList.
1410                 /// </summary>
1411                 public MemberList (IList first, IList second)
1412                 {
1413                         ArrayList list = new ArrayList ();
1414                         list.AddRange (first);
1415                         list.AddRange (second);
1416                         count = list.Count;
1417                         List = list;
1418                 }
1419
1420                 public static readonly MemberList Empty = new MemberList (new ArrayList ());
1421
1422                 /// <summary>
1423                 ///   Cast the MemberList into a MemberInfo[] array.
1424                 /// </summary>
1425                 /// <remarks>
1426                 ///   This is an expensive operation, only use it if it's really necessary.
1427                 /// </remarks>
1428                 public static explicit operator MemberInfo [] (MemberList list)
1429                 {
1430                         Timer.StartTimer (TimerType.MiscTimer);
1431                         MemberInfo [] result = new MemberInfo [list.Count];
1432                         list.CopyTo (result, 0);
1433                         Timer.StopTimer (TimerType.MiscTimer);
1434                         return result;
1435                 }
1436
1437                 // ICollection
1438
1439                 public int Count {
1440                         get {
1441                                 return count;
1442                         }
1443                 }
1444
1445                 public bool IsSynchronized {
1446                         get {
1447                                 return List.IsSynchronized;
1448                         }
1449                 }
1450
1451                 public object SyncRoot {
1452                         get {
1453                                 return List.SyncRoot;
1454                         }
1455                 }
1456
1457                 public void CopyTo (Array array, int index)
1458                 {
1459                         List.CopyTo (array, index);
1460                 }
1461
1462                 // IEnumerable
1463
1464                 public IEnumerator GetEnumerator ()
1465                 {
1466                         return List.GetEnumerator ();
1467                 }
1468
1469                 // IList
1470
1471                 public bool IsFixedSize {
1472                         get {
1473                                 return true;
1474                         }
1475                 }
1476
1477                 public bool IsReadOnly {
1478                         get {
1479                                 return true;
1480                         }
1481                 }
1482
1483                 object IList.this [int index] {
1484                         get {
1485                                 return List [index];
1486                         }
1487
1488                         set {
1489                                 throw new NotSupportedException ();
1490                         }
1491                 }
1492
1493                 // FIXME: try to find out whether we can avoid the cast in this indexer.
1494                 public MemberInfo this [int index] {
1495                         get {
1496                                 return (MemberInfo) List [index];
1497                         }
1498                 }
1499
1500                 public int Add (object value)
1501                 {
1502                         throw new NotSupportedException ();
1503                 }
1504
1505                 public void Clear ()
1506                 {
1507                         throw new NotSupportedException ();
1508                 }
1509
1510                 public bool Contains (object value)
1511                 {
1512                         return List.Contains (value);
1513                 }
1514
1515                 public int IndexOf (object value)
1516                 {
1517                         return List.IndexOf (value);
1518                 }
1519
1520                 public void Insert (int index, object value)
1521                 {
1522                         throw new NotSupportedException ();
1523                 }
1524
1525                 public void Remove (object value)
1526                 {
1527                         throw new NotSupportedException ();
1528                 }
1529
1530                 public void RemoveAt (int index)
1531                 {
1532                         throw new NotSupportedException ();
1533                 }
1534         }
1535
1536         /// <summary>
1537         ///   This interface is used to get all members of a class when creating the
1538         ///   member cache.  It must be implemented by all DeclSpace derivatives which
1539         ///   want to support the member cache and by TypeHandle to get caching of
1540         ///   non-dynamic types.
1541         /// </summary>
1542         public interface IMemberContainer {
1543                 /// <summary>
1544                 ///   The name of the IMemberContainer.  This is only used for
1545                 ///   debugging purposes.
1546                 /// </summary>
1547                 string Name {
1548                         get;
1549                 }
1550
1551                 /// <summary>
1552                 ///   The type of this IMemberContainer.
1553                 /// </summary>
1554                 Type Type {
1555                         get;
1556                 }
1557
1558                 /// <summary>
1559                 ///   Returns the IMemberContainer of the parent class or null if this
1560                 ///   is an interface or TypeManger.object_type.
1561                 ///   This is used when creating the member cache for a class to get all
1562                 ///   members from the parent class.
1563                 /// </summary>
1564                 MemberCache ParentCache {
1565                         get;
1566                 }
1567
1568                 /// <summary>
1569                 ///   Whether this is an interface.
1570                 /// </summary>
1571                 bool IsInterface {
1572                         get;
1573                 }
1574
1575                 /// <summary>
1576                 ///   Returns all members of this class with the corresponding MemberTypes
1577                 ///   and BindingFlags.
1578                 /// </summary>
1579                 /// <remarks>
1580                 ///   When implementing this method, make sure not to return any inherited
1581                 ///   members and check the MemberTypes and BindingFlags properly.
1582                 ///   Unfortunately, System.Reflection is lame and doesn't provide a way to
1583                 ///   get the BindingFlags (static/non-static,public/non-public) in the
1584                 ///   MemberInfo class, but the cache needs this information.  That's why
1585                 ///   this method is called multiple times with different BindingFlags.
1586                 /// </remarks>
1587                 MemberList GetMembers (MemberTypes mt, BindingFlags bf);
1588
1589                 /// <summary>
1590                 ///   Return the container's member cache.
1591                 /// </summary>
1592                 MemberCache MemberCache {
1593                         get;
1594                 }
1595         }
1596
1597         /// <summary>
1598         ///   The MemberCache is used by dynamic and non-dynamic types to speed up
1599         ///   member lookups.  It has a member name based hash table; it maps each member
1600         ///   name to a list of CacheEntry objects.  Each CacheEntry contains a MemberInfo
1601         ///   and the BindingFlags that were initially used to get it.  The cache contains
1602         ///   all members of the current class and all inherited members.  If this cache is
1603         ///   for an interface types, it also contains all inherited members.
1604         ///
1605         ///   There are two ways to get a MemberCache:
1606         ///   * if this is a dynamic type, lookup the corresponding DeclSpace and then
1607         ///     use the DeclSpace.MemberCache property.
1608         ///   * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
1609         ///     TypeHandle instance for the type and then use TypeHandle.MemberCache.
1610         /// </summary>
1611         public class MemberCache {
1612                 public readonly IMemberContainer Container;
1613                 protected Hashtable member_hash;
1614                 protected Hashtable method_hash;
1615
1616                 /// <summary>
1617                 ///   Create a new MemberCache for the given IMemberContainer `container'.
1618                 /// </summary>
1619                 public MemberCache (IMemberContainer container)
1620                 {
1621                         this.Container = container;
1622
1623                         Timer.IncrementCounter (CounterType.MemberCache);
1624                         Timer.StartTimer (TimerType.CacheInit);
1625
1626                         // If we have a parent class (we have a parent class unless we're
1627                         // TypeManager.object_type), we deep-copy its MemberCache here.
1628                         if (Container.ParentCache != null)
1629                                 member_hash = SetupCache (Container.ParentCache);
1630                         else
1631                                 member_hash = new Hashtable ();
1632
1633                         // If this is neither a dynamic type nor an interface, create a special
1634                         // method cache with all declared and inherited methods.
1635                         Type type = container.Type;
1636                         if (!(type is TypeBuilder) && !type.IsInterface && !type.IsGenericParameter) {
1637                                 method_hash = new Hashtable ();
1638                                 AddMethods (type);
1639                         }
1640
1641                         // Add all members from the current class.
1642                         AddMembers (Container);
1643
1644                         Timer.StopTimer (TimerType.CacheInit);
1645                 }
1646
1647                 public MemberCache (Type[] ifaces)
1648                 {
1649                         //
1650                         // The members of this cache all belong to other caches.  
1651                         // So, 'Container' will not be used.
1652                         //
1653                         this.Container = null;
1654
1655                         member_hash = new Hashtable ();
1656                         if (ifaces == null)
1657                                 return;
1658
1659                         foreach (Type itype in ifaces)
1660                                 AddCacheContents (TypeManager.LookupMemberCache (itype));
1661                 }
1662
1663                 /// <summary>
1664                 ///   Bootstrap this member cache by doing a deep-copy of our parent.
1665                 /// </summary>
1666                 Hashtable SetupCache (MemberCache parent)
1667                 {
1668                         Hashtable hash = new Hashtable ();
1669
1670                         if (parent == null)
1671                                 return hash;
1672
1673                         IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
1674                         while (it.MoveNext ()) {
1675                                 hash [it.Key] = ((ArrayList) it.Value).Clone ();
1676                         }
1677                                 
1678                         return hash;
1679                 }
1680
1681                 /// <summary>
1682                 ///   Add the contents of `cache' to the member_hash.
1683                 /// </summary>
1684                 void AddCacheContents (MemberCache cache)
1685                 {
1686                         IDictionaryEnumerator it = cache.member_hash.GetEnumerator ();
1687                         while (it.MoveNext ()) {
1688                                 ArrayList list = (ArrayList) member_hash [it.Key];
1689                                 if (list == null)
1690                                         member_hash [it.Key] = list = new ArrayList ();
1691
1692                                 ArrayList entries = (ArrayList) it.Value;
1693                                 for (int i = entries.Count-1; i >= 0; i--) {
1694                                         CacheEntry entry = (CacheEntry) entries [i];
1695
1696                                         if (entry.Container != cache.Container)
1697                                                 break;
1698                                         list.Add (entry);
1699                                 }
1700                         }
1701                 }
1702
1703                 /// <summary>
1704                 ///   Add all members from class `container' to the cache.
1705                 /// </summary>
1706                 void AddMembers (IMemberContainer container)
1707                 {
1708                         // We need to call AddMembers() with a single member type at a time
1709                         // to get the member type part of CacheEntry.EntryType right.
1710                         if (!container.IsInterface) {
1711                         AddMembers (MemberTypes.Constructor, container);
1712                         AddMembers (MemberTypes.Field, container);
1713                         }
1714                         AddMembers (MemberTypes.Method, container);
1715                         AddMembers (MemberTypes.Property, container);
1716                         AddMembers (MemberTypes.Event, container);
1717                         // Nested types are returned by both Static and Instance searches.
1718                         AddMembers (MemberTypes.NestedType,
1719                                     BindingFlags.Static | BindingFlags.Public, container);
1720                         AddMembers (MemberTypes.NestedType,
1721                                     BindingFlags.Static | BindingFlags.NonPublic, container);
1722                 }
1723
1724                 void AddMembers (MemberTypes mt, IMemberContainer container)
1725                 {
1726                         AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
1727                         AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
1728                         AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
1729                         AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
1730                 }
1731
1732                 /// <summary>
1733                 ///   Add all members from class `container' with the requested MemberTypes and
1734                 ///   BindingFlags to the cache.  This method is called multiple times with different
1735                 ///   MemberTypes and BindingFlags.
1736                 /// </summary>
1737                 void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
1738                 {
1739                         MemberList members = container.GetMembers (mt, bf);
1740
1741                         foreach (MemberInfo member in members) {
1742                                 string name = member.Name;
1743
1744                                 int pos = name.IndexOf ('<');
1745                                 if (pos > 0)
1746                                         name = name.Substring (0, pos);
1747
1748                                 // We use a name-based hash table of ArrayList's.
1749                                 ArrayList list = (ArrayList) member_hash [name];
1750                                 if (list == null) {
1751                                         list = new ArrayList ();
1752                                         member_hash.Add (name, list);
1753                                 }
1754
1755                                 // When this method is called for the current class, the list will
1756                                 // already contain all inherited members from our parent classes.
1757                                 // We cannot add new members in front of the list since this'd be an
1758                                 // expensive operation, that's why the list is sorted in reverse order
1759                                 // (ie. members from the current class are coming last).
1760                                 list.Add (new CacheEntry (container, member, mt, bf));
1761                         }
1762                 }
1763
1764                 /// <summary>
1765                 ///   Add all declared and inherited methods from class `type' to the method cache.
1766                 /// </summary>
1767                 void AddMethods (Type type)
1768                 {
1769                         AddMethods (BindingFlags.Static | BindingFlags.Public |
1770                                     BindingFlags.FlattenHierarchy, type);
1771                         AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
1772                                     BindingFlags.FlattenHierarchy, type);
1773                         AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
1774                         AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
1775                 }
1776
1777                 void AddMethods (BindingFlags bf, Type type)
1778                 {
1779                         MemberInfo [] members = type.GetMethods (bf);
1780
1781                         Array.Reverse (members);
1782
1783                         foreach (MethodBase member in members) {
1784                                 string name = member.Name;
1785
1786                                 // We use a name-based hash table of ArrayList's.
1787                                 ArrayList list = (ArrayList) method_hash [name];
1788                                 if (list == null) {
1789                                         list = new ArrayList ();
1790                                         method_hash.Add (name, list);
1791                                 }
1792
1793                                 // Unfortunately, the elements returned by Type.GetMethods() aren't
1794                                 // sorted so we need to do this check for every member.
1795                                 BindingFlags new_bf = bf;
1796                                 if (member.DeclaringType == type)
1797                                         new_bf |= BindingFlags.DeclaredOnly;
1798
1799                                 list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
1800                         }
1801                 }
1802
1803                 /// <summary>
1804                 ///   Compute and return a appropriate `EntryType' magic number for the given
1805                 ///   MemberTypes and BindingFlags.
1806                 /// </summary>
1807                 protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
1808                 {
1809                         EntryType type = EntryType.None;
1810
1811                         if ((mt & MemberTypes.Constructor) != 0)
1812                                 type |= EntryType.Constructor;
1813                         if ((mt & MemberTypes.Event) != 0)
1814                                 type |= EntryType.Event;
1815                         if ((mt & MemberTypes.Field) != 0)
1816                                 type |= EntryType.Field;
1817                         if ((mt & MemberTypes.Method) != 0)
1818                                 type |= EntryType.Method;
1819                         if ((mt & MemberTypes.Property) != 0)
1820                                 type |= EntryType.Property;
1821                         // Nested types are returned by static and instance searches.
1822                         if ((mt & MemberTypes.NestedType) != 0)
1823                                 type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
1824
1825                         if ((bf & BindingFlags.Instance) != 0)
1826                                 type |= EntryType.Instance;
1827                         if ((bf & BindingFlags.Static) != 0)
1828                                 type |= EntryType.Static;
1829                         if ((bf & BindingFlags.Public) != 0)
1830                                 type |= EntryType.Public;
1831                         if ((bf & BindingFlags.NonPublic) != 0)
1832                                 type |= EntryType.NonPublic;
1833                         if ((bf & BindingFlags.DeclaredOnly) != 0)
1834                                 type |= EntryType.Declared;
1835
1836                         return type;
1837                 }
1838
1839                 /// <summary>
1840                 ///   The `MemberTypes' enumeration type is a [Flags] type which means that it may
1841                 ///   denote multiple member types.  Returns true if the given flags value denotes a
1842                 ///   single member types.
1843                 /// </summary>
1844                 public static bool IsSingleMemberType (MemberTypes mt)
1845                 {
1846                         switch (mt) {
1847                         case MemberTypes.Constructor:
1848                         case MemberTypes.Event:
1849                         case MemberTypes.Field:
1850                         case MemberTypes.Method:
1851                         case MemberTypes.Property:
1852                         case MemberTypes.NestedType:
1853                                 return true;
1854
1855                         default:
1856                                 return false;
1857                         }
1858                 }
1859
1860                 /// <summary>
1861                 ///   We encode the MemberTypes and BindingFlags of each members in a "magic"
1862                 ///   number to speed up the searching process.
1863                 /// </summary>
1864                 [Flags]
1865                 protected enum EntryType {
1866                         None            = 0x000,
1867
1868                         Instance        = 0x001,
1869                         Static          = 0x002,
1870                         MaskStatic      = Instance|Static,
1871
1872                         Public          = 0x004,
1873                         NonPublic       = 0x008,
1874                         MaskProtection  = Public|NonPublic,
1875
1876                         Declared        = 0x010,
1877
1878                         Constructor     = 0x020,
1879                         Event           = 0x040,
1880                         Field           = 0x080,
1881                         Method          = 0x100,
1882                         Property        = 0x200,
1883                         NestedType      = 0x400,
1884
1885                         MaskType        = Constructor|Event|Field|Method|Property|NestedType
1886                 }
1887
1888                 protected struct CacheEntry {
1889                         public readonly IMemberContainer Container;
1890                         public readonly EntryType EntryType;
1891                         public readonly MemberInfo Member;
1892
1893                         public CacheEntry (IMemberContainer container, MemberInfo member,
1894                                            MemberTypes mt, BindingFlags bf)
1895                         {
1896                                 this.Container = container;
1897                                 this.Member = member;
1898                                 this.EntryType = GetEntryType (mt, bf);
1899                         }
1900
1901                         public override string ToString ()
1902                         {
1903                                 return String.Format ("CacheEntry ({0}:{1}:{2})", Container.Name,
1904                                                       EntryType, Member);
1905                         }
1906                 }
1907
1908                 /// <summary>
1909                 ///   This is called each time we're walking up one level in the class hierarchy
1910                 ///   and checks whether we can abort the search since we've already found what
1911                 ///   we were looking for.
1912                 /// </summary>
1913                 protected bool DoneSearching (ArrayList list)
1914                 {
1915                         //
1916                         // We've found exactly one member in the current class and it's not
1917                         // a method or constructor.
1918                         //
1919                         if (list.Count == 1 && !(list [0] is MethodBase))
1920                                 return true;
1921
1922                         //
1923                         // Multiple properties: we query those just to find out the indexer
1924                         // name
1925                         //
1926                         if ((list.Count > 0) && (list [0] is PropertyInfo))
1927                                 return true;
1928
1929                         return false;
1930                 }
1931
1932                 /// <summary>
1933                 ///   Looks up members with name `name'.  If you provide an optional
1934                 ///   filter function, it'll only be called with members matching the
1935                 ///   requested member name.
1936                 ///
1937                 ///   This method will try to use the cache to do the lookup if possible.
1938                 ///
1939                 ///   Unlike other FindMembers implementations, this method will always
1940                 ///   check all inherited members - even when called on an interface type.
1941                 ///
1942                 ///   If you know that you're only looking for methods, you should use
1943                 ///   MemberTypes.Method alone since this speeds up the lookup a bit.
1944                 ///   When doing a method-only search, it'll try to use a special method
1945                 ///   cache (unless it's a dynamic type or an interface) and the returned
1946                 ///   MemberInfo's will have the correct ReflectedType for inherited methods.
1947                 ///   The lookup process will automatically restart itself in method-only
1948                 ///   search mode if it discovers that it's about to return methods.
1949                 /// </summary>
1950                 ArrayList global = new ArrayList ();
1951                 bool using_global = false;
1952                 
1953                 static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
1954                 
1955                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
1956                                                MemberFilter filter, object criteria)
1957                 {
1958                         if (using_global)
1959                                 throw new Exception ();
1960                         
1961                         bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
1962                         bool method_search = mt == MemberTypes.Method;
1963                         // If we have a method cache and we aren't already doing a method-only search,
1964                         // then we restart a method search if the first match is a method.
1965                         bool do_method_search = !method_search && (method_hash != null);
1966
1967                         ArrayList applicable;
1968
1969                         // If this is a method-only search, we try to use the method cache if
1970                         // possible; a lookup in the method cache will return a MemberInfo with
1971                         // the correct ReflectedType for inherited methods.
1972                         
1973                         if (method_search && (method_hash != null))
1974                                 applicable = (ArrayList) method_hash [name];
1975                         else
1976                                 applicable = (ArrayList) member_hash [name];
1977
1978                         if (applicable == null)
1979                                 return emptyMemberInfo;
1980
1981                         //
1982                         // 32  slots gives 53 rss/54 size
1983                         // 2/4 slots gives 55 rss
1984                         //
1985                         // Strange: from 25,000 calls, only 1,800
1986                         // are above 2.  Why does this impact it?
1987                         //
1988                         global.Clear ();
1989                         using_global = true;
1990
1991                         Timer.StartTimer (TimerType.CachedLookup);
1992
1993                         EntryType type = GetEntryType (mt, bf);
1994
1995                         IMemberContainer current = Container;
1996
1997
1998                         // `applicable' is a list of all members with the given member name `name'
1999                         // in the current class and all its parent classes.  The list is sorted in
2000                         // reverse order due to the way how the cache is initialy created (to speed
2001                         // things up, we're doing a deep-copy of our parent).
2002
2003                         for (int i = applicable.Count-1; i >= 0; i--) {
2004                                 CacheEntry entry = (CacheEntry) applicable [i];
2005
2006                                 // This happens each time we're walking one level up in the class
2007                                 // hierarchy.  If we're doing a DeclaredOnly search, we must abort
2008                                 // the first time this happens (this may already happen in the first
2009                                 // iteration of this loop if there are no members with the name we're
2010                                 // looking for in the current class).
2011                                 if (entry.Container != current) {
2012                                         if (declared_only || DoneSearching (global))
2013                                                 break;
2014
2015                                         current = entry.Container;
2016                                 }
2017
2018                                 // Is the member of the correct type ?
2019                                 if ((entry.EntryType & type & EntryType.MaskType) == 0)
2020                                         continue;
2021
2022                                 // Is the member static/non-static ?
2023                                 if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
2024                                         continue;
2025
2026                                 // Apply the filter to it.
2027                                 if (filter (entry.Member, criteria)) {
2028                                         if ((entry.EntryType & EntryType.MaskType) != EntryType.Method)
2029                                                 do_method_search = false;
2030                                         global.Add (entry.Member);
2031                                 }
2032                         }
2033
2034                         Timer.StopTimer (TimerType.CachedLookup);
2035
2036                         // If we have a method cache and we aren't already doing a method-only
2037                         // search, we restart in method-only search mode if the first match is
2038                         // a method.  This ensures that we return a MemberInfo with the correct
2039                         // ReflectedType for inherited methods.
2040                         if (do_method_search && (global.Count > 0)){
2041                                 using_global = false;
2042
2043                                 return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
2044                         }
2045
2046                         using_global = false;
2047                         MemberInfo [] copy = new MemberInfo [global.Count];
2048                         global.CopyTo (copy);
2049                         return copy;
2050                 }
2051                 
2052                 //
2053                 // This finds the method or property for us to override. invocationType is the type where
2054                 // the override is going to be declared, name is the name of the method/property, and
2055                 // paramTypes is the parameters, if any to the method or property
2056                 //
2057                 // Because the MemberCache holds members from this class and all the base classes,
2058                 // we can avoid tons of reflection stuff.
2059                 //
2060                 public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, bool is_property)
2061                 {
2062                         ArrayList applicable;
2063                         if (method_hash != null && !is_property)
2064                                 applicable = (ArrayList) method_hash [name];
2065                         else
2066                                 applicable = (ArrayList) member_hash [name];
2067                         
2068                         if (applicable == null)
2069                                 return null;
2070                         //
2071                         // Walk the chain of methods, starting from the top.
2072                         //
2073                         for (int i = applicable.Count - 1; i >= 0; i--) {
2074                                 CacheEntry entry = (CacheEntry) applicable [i];
2075                                 
2076                                 if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
2077                                         continue;
2078
2079                                 PropertyInfo pi = null;
2080                                 MethodInfo mi = null;
2081                                 FieldInfo fi = null;
2082                                 Type [] cmpAttrs = null;
2083                                 
2084                                 if (is_property) {
2085                                         if ((entry.EntryType & EntryType.Field) != 0) {
2086                                                 fi = (FieldInfo)entry.Member;
2087
2088                                                 // TODO: For this case we ignore member type
2089                                                 //fb = TypeManager.GetField (fi);
2090                                                 //cmpAttrs = new Type[] { fb.MemberType };
2091                                         } else {
2092                                                 pi = (PropertyInfo) entry.Member;
2093                                                 cmpAttrs = TypeManager.GetArgumentTypes (pi);
2094                                         }
2095                                 } else {
2096                                         mi = (MethodInfo) entry.Member;
2097                                         cmpAttrs = TypeManager.GetArgumentTypes (mi);
2098                                 }
2099
2100                                 if (fi != null) {
2101                                         // TODO: Almost duplicate !
2102                                         // Check visibility
2103                                         switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
2104                                                 case FieldAttributes.Private:
2105                                                         //
2106                                                         // A private method is Ok if we are a nested subtype.
2107                                                         // The spec actually is not very clear about this, see bug 52458.
2108                                                         //
2109                                                         if (invocationType != entry.Container.Type &
2110                                                                 TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
2111                                                                 continue;
2112
2113                                                         break;
2114                                                 case FieldAttributes.FamANDAssem:
2115                                                 case FieldAttributes.Assembly:
2116                                                         //
2117                                                         // Check for assembly methods
2118                                                         //
2119                                                         if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
2120                                                                 continue;
2121                                                         break;
2122                                         }
2123                                         return entry.Member;
2124                                 }
2125
2126                                 //
2127                                 // Check the arguments
2128                                 //
2129                                 if (cmpAttrs.Length != paramTypes.Length)
2130                                         continue;
2131
2132                                 for (int j = cmpAttrs.Length - 1; j >= 0; j --) {
2133                                         if (!TypeManager.IsEqual (paramTypes [j], cmpAttrs [j]))
2134                                                 goto next;
2135                                 }
2136                                 
2137                                 //
2138                                 // get one of the methods because this has the visibility info.
2139                                 //
2140                                 if (is_property) {
2141                                         mi = pi.GetGetMethod (true);
2142                                         if (mi == null)
2143                                                 mi = pi.GetSetMethod (true);
2144                                 }
2145                                 
2146                                 //
2147                                 // Check visibility
2148                                 //
2149                                 switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
2150                                 case MethodAttributes.Private:
2151                                         //
2152                                         // A private method is Ok if we are a nested subtype.
2153                                         // The spec actually is not very clear about this, see bug 52458.
2154                                         //
2155                                         if (invocationType.Equals (entry.Container.Type) ||
2156                                             TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
2157                                                 return entry.Member;
2158                                         
2159                                         break;
2160                                 case MethodAttributes.FamANDAssem:
2161                                 case MethodAttributes.Assembly:
2162                                         //
2163                                         // Check for assembly methods
2164                                         //
2165                                         if (mi.DeclaringType.Assembly == CodeGen.Assembly.Builder)
2166                                                 return entry.Member;
2167                                         
2168                                         break;
2169                                 default:
2170                                         //
2171                                         // A protected method is ok, because we are overriding.
2172                                         // public is always ok.
2173                                         //
2174                                         return entry.Member;
2175                                 }
2176                         next:
2177                                 ;
2178                         }
2179                         
2180                         return null;
2181                 }
2182
2183                 /// <summary>
2184                 /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
2185                 /// We handle two cases. The first is for types without parameters (events, field, properties).
2186                 /// The second are methods, indexers and this is why ignore_complex_types is here.
2187                 /// The latest param is temporary hack. See DoDefineMembers method for more info.
2188                 /// </summary>
2189                 public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
2190                 {
2191                         ArrayList applicable = null;
2192  
2193                         if (method_hash != null)
2194                                 applicable = (ArrayList) method_hash [name];
2195  
2196                         if (applicable != null) {
2197                                 for (int i = applicable.Count - 1; i >= 0; i--) {
2198                                         CacheEntry entry = (CacheEntry) applicable [i];
2199                                         if ((entry.EntryType & EntryType.Public) != 0)
2200                                                 return entry.Member;
2201                                 }
2202                         }
2203  
2204                         if (member_hash == null)
2205                                 return null;
2206                         applicable = (ArrayList) member_hash [name];
2207                         
2208                         if (applicable != null) {
2209                                 for (int i = applicable.Count - 1; i >= 0; i--) {
2210                                         CacheEntry entry = (CacheEntry) applicable [i];
2211                                         if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
2212                                                 if (ignore_complex_types) {
2213                                                         if ((entry.EntryType & EntryType.Method) != 0)
2214                                                                 continue;
2215  
2216                                                         // Does exist easier way how to detect indexer ?
2217                                                         if ((entry.EntryType & EntryType.Property) != 0) {
2218                                                                 Type[] arg_types = TypeManager.GetArgumentTypes ((PropertyInfo)entry.Member);
2219                                                                 if (arg_types.Length > 0)
2220                                                                         continue;
2221                                                         }
2222                                                 }
2223                                                 return entry.Member;
2224                                         }
2225                                 }
2226                         }
2227                         return null;
2228                 }
2229
2230                 Hashtable locase_table;
2231  
2232                 /// <summary>
2233                 /// Builds low-case table for CLS Compliance test
2234                 /// </summary>
2235                 public Hashtable GetPublicMembers ()
2236                 {
2237                         if (locase_table != null)
2238                                 return locase_table;
2239  
2240                         locase_table = new Hashtable ();
2241                         foreach (DictionaryEntry entry in member_hash) {
2242                                 ArrayList members = (ArrayList)entry.Value;
2243                                 for (int ii = 0; ii < members.Count; ++ii) {
2244                                         CacheEntry member_entry = (CacheEntry) members [ii];
2245  
2246                                         if ((member_entry.EntryType & EntryType.Public) == 0)
2247                                                 continue;
2248  
2249                                         // TODO: Does anyone know easier way how to detect that member is internal ?
2250                                         switch (member_entry.EntryType & EntryType.MaskType) {
2251                                                 case EntryType.Constructor:
2252                                                         continue;
2253  
2254                                                 case EntryType.Field:
2255                                                         if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
2256                                                                 continue;
2257                                                         break;
2258  
2259                                                 case EntryType.Method:
2260                                                         if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2261                                                                 continue;
2262                                                         break;
2263  
2264                                                 case EntryType.Property:
2265                                                         PropertyInfo pi = (PropertyInfo)member_entry.Member;
2266                                                         if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
2267                                                                 continue;
2268                                                         break;
2269  
2270                                                 case EntryType.Event:
2271                                                         EventInfo ei = (EventInfo)member_entry.Member;
2272                                                         MethodInfo mi = ei.GetAddMethod ();
2273                                                         if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2274                                                                 continue;
2275                                                         break;
2276                                         }
2277                                         string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
2278                                         locase_table [lcase] = member_entry.Member;
2279                                         break;
2280                                 }
2281                         }
2282                         return locase_table;
2283                 }
2284  
2285                 public Hashtable Members {
2286                         get {
2287                                 return member_hash;
2288                         }
2289                 }
2290  
2291                 /// <summary>
2292                 /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
2293                 /// </summary>
2294                 public void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder)
2295                 {
2296                         EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
2297  
2298                         for (int i = 0; i < al.Count; ++i) {
2299                                 MemberCache.CacheEntry entry = (MemberCache.CacheEntry) al [i];
2300                 
2301                                 // skip itself
2302                                 if (entry.Member == this_builder)
2303                                         continue;
2304                 
2305                                 if ((entry.EntryType & tested_type) != tested_type)
2306                                         continue;
2307                 
2308                                 MethodBase method_to_compare = (MethodBase)entry.Member;
2309                                 if (AttributeTester.AreOverloadedMethodParamsClsCompliant (method.ParameterTypes, TypeManager.GetArgumentTypes (method_to_compare)))
2310                                         continue;
2311
2312                                 IMethodData md = TypeManager.GetMethod (method_to_compare);
2313
2314                                 // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
2315                                 // However it is exactly what csc does.
2316                                 if (md != null && !md.IsClsCompliaceRequired (method.Parent))
2317                                         continue;
2318                 
2319                                 Report.SymbolRelatedToPreviousError (entry.Member);
2320                                 Report.Error (3006, method.Location, "Overloaded method '{0}' differing only in ref or out, or in array rank, is not CLS-compliant", method.GetSignatureForError ());
2321                         }
2322                 }
2323         }
2324 }