Fix all CreateInstance overloads for void
[mcs.git] / mcs / decl.cs
blob6dec53c449f9042e222c853ac840713a735fb683
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 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2004-2008 Novell, Inc
14 using System;
15 using System.Text;
16 using System.Collections;
17 using System.Globalization;
18 using System.Reflection.Emit;
19 using System.Reflection;
21 #if NET_2_1
22 using XmlElement = System.Object;
23 #else
24 using System.Xml;
25 #endif
27 namespace Mono.CSharp {
30 // Better name would be DottenName
32 public class MemberName {
33 public readonly string Name;
34 public readonly TypeArguments TypeArguments;
36 public readonly MemberName Left;
37 public readonly Location Location;
39 public static readonly MemberName Null = new MemberName ("");
41 bool is_double_colon;
43 private MemberName (MemberName left, string name, bool is_double_colon,
44 Location loc)
46 this.Name = name;
47 this.Location = loc;
48 this.is_double_colon = is_double_colon;
49 this.Left = left;
52 private MemberName (MemberName left, string name, bool is_double_colon,
53 TypeArguments args, Location loc)
54 : this (left, name, is_double_colon, loc)
56 if (args != null && args.Count > 0)
57 this.TypeArguments = args;
60 public MemberName (string name)
61 : this (name, Location.Null)
62 { }
64 public MemberName (string name, Location loc)
65 : this (null, name, false, loc)
66 { }
68 public MemberName (string name, TypeArguments args, Location loc)
69 : this (null, name, false, args, loc)
70 { }
72 public MemberName (MemberName left, string name)
73 : this (left, name, left != null ? left.Location : Location.Null)
74 { }
76 public MemberName (MemberName left, string name, Location loc)
77 : this (left, name, false, loc)
78 { }
80 public MemberName (MemberName left, string name, TypeArguments args, Location loc)
81 : this (left, name, false, args, loc)
82 { }
84 public MemberName (string alias, string name, TypeArguments args, Location loc)
85 : this (new MemberName (alias, loc), name, true, args, loc)
86 { }
88 public MemberName (MemberName left, MemberName right)
89 : this (left, right, right.Location)
90 { }
92 public MemberName (MemberName left, MemberName right, Location loc)
93 : this (null, right.Name, false, right.TypeArguments, loc)
95 if (right.is_double_colon)
96 throw new InternalErrorException ("Cannot append double_colon member name");
97 this.Left = (right.Left == null) ? left : new MemberName (left, right.Left);
100 // TODO: Remove
101 public string GetName ()
103 return GetName (false);
106 public bool IsGeneric {
107 get {
108 if (TypeArguments != null)
109 return true;
110 else if (Left != null)
111 return Left.IsGeneric;
112 else
113 return false;
117 public string GetName (bool is_generic)
119 string name = is_generic ? Basename : Name;
120 if (Left != null)
121 return Left.GetName (is_generic) + (is_double_colon ? "::" : ".") + name;
123 return name;
126 public ATypeNameExpression GetTypeExpression ()
128 if (Left == null) {
129 if (TypeArguments != null)
130 return new SimpleName (Basename, TypeArguments, Location);
132 return new SimpleName (Name, Location);
135 if (is_double_colon) {
136 if (Left.Left != null)
137 throw new InternalErrorException ("The left side of a :: should be an identifier");
138 return new QualifiedAliasMember (Left.Name, Name, TypeArguments, Location);
141 Expression lexpr = Left.GetTypeExpression ();
142 return new MemberAccess (lexpr, Name, TypeArguments, Location);
145 public MemberName Clone ()
147 MemberName left_clone = Left == null ? null : Left.Clone ();
148 return new MemberName (left_clone, Name, is_double_colon, TypeArguments, Location);
151 public string Basename {
152 get {
153 if (TypeArguments != null)
154 return MakeName (Name, TypeArguments);
155 return Name;
159 public string GetSignatureForError ()
161 string append = TypeArguments == null ? "" : "<" + TypeArguments.GetSignatureForError () + ">";
162 if (Left == null)
163 return Name + append;
164 string connect = is_double_colon ? "::" : ".";
165 return Left.GetSignatureForError () + connect + Name + append;
168 public override bool Equals (object other)
170 return Equals (other as MemberName);
173 public bool Equals (MemberName other)
175 if (this == other)
176 return true;
177 if (other == null || Name != other.Name)
178 return false;
179 if (is_double_colon != other.is_double_colon)
180 return false;
182 if ((TypeArguments != null) &&
183 (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count))
184 return false;
186 if ((TypeArguments == null) && (other.TypeArguments != null))
187 return false;
189 if (Left == null)
190 return other.Left == null;
192 return Left.Equals (other.Left);
195 public override int GetHashCode ()
197 int hash = Name.GetHashCode ();
198 for (MemberName n = Left; n != null; n = n.Left)
199 hash ^= n.Name.GetHashCode ();
200 if (is_double_colon)
201 hash ^= 0xbadc01d;
203 if (TypeArguments != null)
204 hash ^= TypeArguments.Count << 5;
206 return hash & 0x7FFFFFFF;
209 public int CountTypeArguments {
210 get {
211 if (TypeArguments != null)
212 return TypeArguments.Count;
213 else if (Left != null)
214 return Left.CountTypeArguments;
215 else
216 return 0;
220 public static string MakeName (string name, TypeArguments args)
222 if (args == null)
223 return name;
225 return name + "`" + args.Count;
228 public static string MakeName (string name, int count)
230 return name + "`" + count;
234 /// <summary>
235 /// Base representation for members. This is used to keep track
236 /// of Name, Location and Modifier flags, and handling Attributes.
237 /// </summary>
238 public abstract class MemberCore : Attributable, IMemberContext {
239 /// <summary>
240 /// Public name
241 /// </summary>
243 protected string cached_name;
244 // TODO: Remove in favor of MemberName
245 public string Name {
246 get {
247 if (cached_name == null)
248 cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method));
249 return cached_name;
253 // Is not readonly because of IndexerName attribute
254 private MemberName member_name;
255 public MemberName MemberName {
256 get { return member_name; }
259 /// <summary>
260 /// Modifier flags that the user specified in the source code
261 /// </summary>
262 private int mod_flags;
263 public int ModFlags {
264 set {
265 mod_flags = value;
266 if ((value & Modifiers.COMPILER_GENERATED) != 0)
267 caching_flags = Flags.IsUsed | Flags.IsAssigned;
269 get {
270 return mod_flags;
274 public /*readonly*/ DeclSpace Parent;
276 /// <summary>
277 /// Location where this declaration happens
278 /// </summary>
279 public Location Location {
280 get { return member_name.Location; }
283 /// <summary>
284 /// XML documentation comment
285 /// </summary>
286 protected string comment;
288 /// <summary>
289 /// Represents header string for documentation comment
290 /// for each member types.
291 /// </summary>
292 public abstract string DocCommentHeader { get; }
294 [Flags]
295 public enum Flags {
296 Obsolete_Undetected = 1, // Obsolete attribute has not been detected yet
297 Obsolete = 1 << 1, // Type has obsolete attribute
298 ClsCompliance_Undetected = 1 << 2, // CLS Compliance has not been detected yet
299 ClsCompliant = 1 << 3, // Type is CLS Compliant
300 CloseTypeCreated = 1 << 4, // Tracks whether we have Closed the type
301 HasCompliantAttribute_Undetected = 1 << 5, // Presence of CLSCompliantAttribute has not been detected
302 HasClsCompliantAttribute = 1 << 6, // Type has CLSCompliantAttribute
303 ClsCompliantAttributeTrue = 1 << 7, // Type has CLSCompliant (true)
304 Excluded_Undetected = 1 << 8, // Conditional attribute has not been detected yet
305 Excluded = 1 << 9, // Method is conditional
306 MethodOverloadsExist = 1 << 10, // Test for duplication must be performed
307 IsUsed = 1 << 11,
308 IsAssigned = 1 << 12, // Field is assigned
309 HasExplicitLayout = 1 << 13,
310 PartialDefinitionExists = 1 << 14, // Set when corresponding partial method definition exists
311 HasStructLayout = 1 << 15 // Has StructLayoutAttribute
314 /// <summary>
315 /// MemberCore flags at first detected then cached
316 /// </summary>
317 internal Flags caching_flags;
319 public MemberCore (DeclSpace parent, MemberName name, Attributes attrs)
321 this.Parent = parent;
322 member_name = name;
323 caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected;
324 AddAttributes (attrs, this);
327 protected virtual void SetMemberName (MemberName new_name)
329 member_name = new_name;
330 cached_name = null;
333 protected bool CheckAbstractAndExtern (bool has_block)
335 if (Parent.PartialContainer.Kind == Kind.Interface)
336 return true;
338 if (has_block) {
339 if ((ModFlags & Modifiers.EXTERN) != 0) {
340 Report.Error (179, Location, "`{0}' cannot declare a body because it is marked extern",
341 GetSignatureForError ());
342 return false;
345 if ((ModFlags & Modifiers.ABSTRACT) != 0) {
346 Report.Error (500, Location, "`{0}' cannot declare a body because it is marked abstract",
347 GetSignatureForError ());
348 return false;
350 } else {
351 if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN | Modifiers.PARTIAL)) == 0) {
352 if (RootContext.Version >= LanguageVersion.V_3) {
353 Property.PropertyMethod pm = this as Property.PropertyMethod;
354 if (pm is Indexer.GetIndexerMethod || pm is Indexer.SetIndexerMethod)
355 pm = null;
357 if (pm != null && (pm.Property.Get.IsDummy || pm.Property.Set.IsDummy)) {
358 Report.Error (840, Location,
359 "`{0}' must have a body because it is not marked abstract or extern. The property can be automatically implemented when you define both accessors",
360 GetSignatureForError ());
361 return false;
365 Report.Error (501, Location, "`{0}' must have a body because it is not marked abstract, extern, or partial",
366 GetSignatureForError ());
367 return false;
371 return true;
374 protected void CheckProtectedModifier ()
376 if ((ModFlags & Modifiers.PROTECTED) == 0)
377 return;
379 if (Parent.PartialContainer.Kind == Kind.Struct) {
380 Report.Error (666, Location, "`{0}': Structs cannot contain protected members",
381 GetSignatureForError ());
382 return;
385 if ((Parent.ModFlags & Modifiers.STATIC) != 0) {
386 Report.Error (1057, Location, "`{0}': Static classes cannot contain protected members",
387 GetSignatureForError ());
388 return;
391 if ((Parent.ModFlags & Modifiers.SEALED) != 0 && (ModFlags & Modifiers.OVERRIDE) == 0 &&
392 !(this is Destructor)) {
393 Report.Warning (628, 4, Location, "`{0}': new protected member declared in sealed class",
394 GetSignatureForError ());
395 return;
399 public abstract bool Define ();
401 public virtual string DocComment {
402 get {
403 return comment;
405 set {
406 comment = value;
411 // Returns full member name for error message
413 public virtual string GetSignatureForError ()
415 if (Parent == null || Parent.Parent == null)
416 return member_name.GetSignatureForError ();
418 return Parent.GetSignatureForError () + "." + member_name.GetSignatureForError ();
421 /// <summary>
422 /// Base Emit method. This is also entry point for CLS-Compliant verification.
423 /// </summary>
424 public virtual void Emit ()
426 if (!RootContext.VerifyClsCompliance)
427 return;
429 if (Report.WarningLevel > 0)
430 VerifyClsCompliance ();
433 public bool IsCompilerGenerated {
434 get {
435 if ((mod_flags & Modifiers.COMPILER_GENERATED) != 0)
436 return true;
438 return Parent == null ? false : Parent.IsCompilerGenerated;
442 public virtual bool IsUsed {
443 get { return (caching_flags & Flags.IsUsed) != 0; }
446 protected Report Report {
447 get {
448 return Compiler.Report;
452 public void SetMemberIsUsed ()
454 caching_flags |= Flags.IsUsed;
457 /// <summary>
458 /// Returns instance of ObsoleteAttribute for this MemberCore
459 /// </summary>
460 public virtual ObsoleteAttribute GetObsoleteAttribute ()
462 if ((caching_flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0)
463 return null;
465 caching_flags &= ~Flags.Obsolete_Undetected;
467 if (OptAttributes == null)
468 return null;
470 Attribute obsolete_attr = OptAttributes.Search (PredefinedAttributes.Get.Obsolete);
471 if (obsolete_attr == null)
472 return null;
474 caching_flags |= Flags.Obsolete;
476 ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute ();
477 if (obsolete == null)
478 return null;
480 return obsolete;
483 /// <summary>
484 /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
485 /// </summary>
486 public virtual void CheckObsoleteness (Location loc)
488 ObsoleteAttribute oa = GetObsoleteAttribute ();
489 if (oa != null)
490 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, Report);
493 // Access level of a type.
494 const int X = 1;
495 enum AccessLevel
496 { // Each column represents `is this scope larger or equal to Blah scope'
497 // Public Assembly Protected
498 Protected = (0 << 0) | (0 << 1) | (X << 2),
499 Public = (X << 0) | (X << 1) | (X << 2),
500 Private = (0 << 0) | (0 << 1) | (0 << 2),
501 Internal = (0 << 0) | (X << 1) | (0 << 2),
502 ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2),
505 static AccessLevel GetAccessLevelFromModifiers (int flags)
507 if ((flags & Modifiers.INTERNAL) != 0) {
509 if ((flags & Modifiers.PROTECTED) != 0)
510 return AccessLevel.ProtectedOrInternal;
511 else
512 return AccessLevel.Internal;
514 } else if ((flags & Modifiers.PROTECTED) != 0)
515 return AccessLevel.Protected;
516 else if ((flags & Modifiers.PRIVATE) != 0)
517 return AccessLevel.Private;
518 else
519 return AccessLevel.Public;
523 // Returns the access level for type `t'
525 static AccessLevel GetAccessLevelFromType (Type t)
527 if (t.IsPublic)
528 return AccessLevel.Public;
529 if (t.IsNestedPrivate)
530 return AccessLevel.Private;
531 if (t.IsNotPublic)
532 return AccessLevel.Internal;
534 if (t.IsNestedPublic)
535 return AccessLevel.Public;
536 if (t.IsNestedAssembly)
537 return AccessLevel.Internal;
538 if (t.IsNestedFamily)
539 return AccessLevel.Protected;
540 if (t.IsNestedFamORAssem)
541 return AccessLevel.ProtectedOrInternal;
542 if (t.IsNestedFamANDAssem)
543 throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
545 // nested private is taken care of
547 throw new Exception ("I give up, what are you?");
551 // Checks whether the type P is as accessible as this member
553 public bool IsAccessibleAs (Type p)
556 // if M is private, its accessibility is the same as this declspace.
557 // we already know that P is accessible to T before this method, so we
558 // may return true.
560 if ((mod_flags & Modifiers.PRIVATE) != 0)
561 return true;
563 while (TypeManager.HasElementType (p))
564 p = TypeManager.GetElementType (p);
566 if (TypeManager.IsGenericParameter (p))
567 return true;
569 if (TypeManager.IsGenericType (p)) {
570 foreach (Type t in TypeManager.GetTypeArguments (p)) {
571 if (!IsAccessibleAs (t))
572 return false;
576 for (Type p_parent = null; p != null; p = p_parent) {
577 p_parent = p.DeclaringType;
578 AccessLevel pAccess = GetAccessLevelFromType (p);
579 if (pAccess == AccessLevel.Public)
580 continue;
582 bool same_access_restrictions = false;
583 for (MemberCore mc = this; !same_access_restrictions && mc != null && mc.Parent != null; mc = mc.Parent) {
584 AccessLevel al = GetAccessLevelFromModifiers (mc.ModFlags);
585 switch (pAccess) {
586 case AccessLevel.Internal:
587 if (al == AccessLevel.Private || al == AccessLevel.Internal)
588 same_access_restrictions = TypeManager.IsThisOrFriendAssembly (Parent.Module.Assembly, p.Assembly);
590 break;
592 case AccessLevel.Protected:
593 if (al == AccessLevel.Protected) {
594 same_access_restrictions = mc.Parent.IsBaseType (p_parent);
595 break;
598 if (al == AccessLevel.Private) {
600 // When type is private and any of its parents derives from
601 // protected type then the type is accessible
603 while (mc.Parent != null) {
604 if (mc.Parent.IsBaseType (p_parent))
605 same_access_restrictions = true;
606 mc = mc.Parent;
610 break;
612 case AccessLevel.ProtectedOrInternal:
613 if (al == AccessLevel.Protected)
614 same_access_restrictions = mc.Parent.IsBaseType (p_parent);
615 else if (al == AccessLevel.Internal)
616 same_access_restrictions = TypeManager.IsThisOrFriendAssembly (Parent.Module.Assembly, p.Assembly);
617 else if (al == AccessLevel.ProtectedOrInternal)
618 same_access_restrictions = mc.Parent.IsBaseType (p_parent) &&
619 TypeManager.IsThisOrFriendAssembly (Parent.Module.Assembly, p.Assembly);
621 break;
623 case AccessLevel.Private:
625 // Both are private and share same parent
627 if (al == AccessLevel.Private)
628 same_access_restrictions = TypeManager.IsEqual (mc.Parent.TypeBuilder, p_parent);
630 break;
632 default:
633 throw new InternalErrorException (al.ToString ());
637 if (!same_access_restrictions)
638 return false;
641 return true;
644 /// <summary>
645 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
646 /// </summary>
647 public override bool IsClsComplianceRequired ()
649 if ((caching_flags & Flags.ClsCompliance_Undetected) == 0)
650 return (caching_flags & Flags.ClsCompliant) != 0;
652 if (GetClsCompliantAttributeValue () && IsExposedFromAssembly ()) {
653 caching_flags &= ~Flags.ClsCompliance_Undetected;
654 caching_flags |= Flags.ClsCompliant;
655 return true;
658 caching_flags &= ~Flags.ClsCompliance_Undetected;
659 return false;
662 /// <summary>
663 /// Returns true when MemberCore is exposed from assembly.
664 /// </summary>
665 public bool IsExposedFromAssembly ()
667 if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
668 return false;
670 DeclSpace parentContainer = Parent;
671 while (parentContainer != null && parentContainer.ModFlags != 0) {
672 if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
673 return false;
674 parentContainer = parentContainer.Parent;
676 return true;
679 public virtual ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
681 return Parent.LookupExtensionMethod (extensionType, name, loc);
684 public virtual FullNamedExpression LookupNamespaceAlias (string name)
686 return Parent.NamespaceEntry.LookupNamespaceAlias (name);
689 public virtual FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
691 return Parent.LookupNamespaceOrType (name, loc, ignore_cs0104);
694 /// <summary>
695 /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute.
696 /// If no is attribute exists then assembly CLSCompliantAttribute is returned.
697 /// </summary>
698 public virtual bool GetClsCompliantAttributeValue ()
700 if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0)
701 return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0;
703 caching_flags &= ~Flags.HasCompliantAttribute_Undetected;
705 if (OptAttributes != null) {
706 Attribute cls_attribute = OptAttributes.Search (
707 PredefinedAttributes.Get.CLSCompliant);
708 if (cls_attribute != null) {
709 caching_flags |= Flags.HasClsCompliantAttribute;
710 bool value = cls_attribute.GetClsCompliantAttributeValue ();
711 if (value)
712 caching_flags |= Flags.ClsCompliantAttributeTrue;
713 return value;
717 // It's null for TypeParameter
718 if (Parent == null)
719 return false;
721 if (Parent.GetClsCompliantAttributeValue ()) {
722 caching_flags |= Flags.ClsCompliantAttributeTrue;
723 return true;
725 return false;
728 /// <summary>
729 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
730 /// </summary>
731 protected bool HasClsCompliantAttribute {
732 get {
733 if ((caching_flags & Flags.HasCompliantAttribute_Undetected) != 0)
734 GetClsCompliantAttributeValue ();
736 return (caching_flags & Flags.HasClsCompliantAttribute) != 0;
740 /// <summary>
741 /// Returns true when a member supports multiple overloads (methods, indexers, etc)
742 /// </summary>
743 public virtual bool EnableOverloadChecks (MemberCore overload)
745 return false;
748 /// <summary>
749 /// The main virtual method for CLS-Compliant verifications.
750 /// The method returns true if member is CLS-Compliant and false if member is not
751 /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
752 /// and add their extra verifications.
753 /// </summary>
754 protected virtual bool VerifyClsCompliance ()
756 if (!IsClsComplianceRequired ()) {
757 if (HasClsCompliantAttribute && Report.WarningLevel >= 2) {
758 if (!IsExposedFromAssembly ()) {
759 Attribute a = OptAttributes.Search (PredefinedAttributes.Get.CLSCompliant);
760 Report.Warning (3019, 2, a.Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ());
763 if (!CodeGen.Assembly.IsClsCompliant) {
764 Attribute a = OptAttributes.Search (PredefinedAttributes.Get.CLSCompliant);
765 Report.Warning (3021, 2, a.Location, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ());
768 return false;
771 if (HasClsCompliantAttribute) {
772 if (CodeGen.Assembly.ClsCompliantAttribute == null && !CodeGen.Assembly.IsClsCompliant) {
773 Attribute a = OptAttributes.Search (PredefinedAttributes.Get.CLSCompliant);
774 Report.Warning (3014, 1, a.Location,
775 "`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant",
776 GetSignatureForError ());
777 return false;
780 if (!Parent.IsClsComplianceRequired ()) {
781 Attribute a = OptAttributes.Search (PredefinedAttributes.Get.CLSCompliant);
782 Report.Warning (3018, 1, a.Location, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
783 GetSignatureForError (), Parent.GetSignatureForError ());
784 return false;
788 if (member_name.Name [0] == '_') {
789 Report.Warning (3008, 1, Location, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
791 return true;
795 // Raised (and passed an XmlElement that contains the comment)
796 // when GenerateDocComment is writing documentation expectedly.
798 internal virtual void OnGenerateDocComment (XmlElement intermediateNode)
803 // Returns a string that represents the signature for this
804 // member which should be used in XML documentation.
806 public virtual string GetDocCommentName (DeclSpace ds)
808 if (ds == null || this is DeclSpace)
809 return DocCommentHeader + Name;
810 else
811 return String.Concat (DocCommentHeader, ds.Name, ".", Name);
815 // Generates xml doc comments (if any), and if required,
816 // handle warning report.
818 internal virtual void GenerateDocComment (DeclSpace ds)
820 try {
821 DocUtil.GenerateDocComment (this, ds, Report);
822 } catch (Exception e) {
823 throw new InternalErrorException (this, e);
827 #region IMemberContext Members
829 public virtual CompilerContext Compiler {
830 get { return Parent.Module.Compiler; }
833 public virtual Type CurrentType {
834 get { return Parent.CurrentType; }
837 public virtual TypeContainer CurrentTypeDefinition {
838 get { return Parent.CurrentTypeDefinition; }
841 public virtual TypeParameter[] CurrentTypeParameters {
842 get { return null; }
845 public bool IsObsolete {
846 get {
847 if (GetObsoleteAttribute () != null)
848 return true;
850 return Parent == null ? false : Parent.IsObsolete;
854 public bool IsUnsafe {
855 get {
856 if ((ModFlags & Modifiers.UNSAFE) != 0)
857 return true;
859 return Parent == null ? false : Parent.IsUnsafe;
863 public bool IsStatic {
864 get { return (ModFlags & Modifiers.STATIC) != 0; }
867 #endregion
870 /// <summary>
871 /// Base class for structs, classes, enumerations and interfaces.
872 /// </summary>
873 /// <remarks>
874 /// They all create new declaration spaces. This
875 /// provides the common foundation for managing those name
876 /// spaces.
877 /// </remarks>
878 public abstract class DeclSpace : MemberCore {
879 /// <summary>
880 /// This points to the actual definition that is being
881 /// created with System.Reflection.Emit
882 /// </summary>
883 public TypeBuilder TypeBuilder;
885 /// <summary>
886 /// If we are a generic type, this is the type we are
887 /// currently defining. We need to lookup members on this
888 /// instead of the TypeBuilder.
889 /// </summary>
890 protected Type currentType;
893 // This is the namespace in which this typecontainer
894 // was declared. We use this to resolve names.
896 public NamespaceEntry NamespaceEntry;
898 private Hashtable Cache = new Hashtable ();
900 public readonly string Basename;
902 protected Hashtable defined_names;
904 public TypeContainer PartialContainer;
906 protected readonly bool is_generic;
907 readonly int count_type_params;
908 protected TypeParameter[] type_params;
909 TypeParameter[] type_param_list;
912 // Whether we are Generic
914 public bool IsGeneric {
915 get {
916 if (is_generic)
917 return true;
918 else if (Parent != null)
919 return Parent.IsGeneric;
920 else
921 return false;
925 static string[] attribute_targets = new string [] { "type" };
927 public DeclSpace (NamespaceEntry ns, DeclSpace parent, MemberName name,
928 Attributes attrs)
929 : base (parent, name, attrs)
931 NamespaceEntry = ns;
932 Basename = name.Basename;
933 defined_names = new Hashtable ();
934 PartialContainer = null;
935 if (name.TypeArguments != null) {
936 is_generic = true;
937 count_type_params = name.TypeArguments.Count;
939 if (parent != null)
940 count_type_params += parent.count_type_params;
943 /// <summary>
944 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
945 /// </summary>
946 protected virtual bool AddToContainer (MemberCore symbol, string name)
948 MemberCore mc = (MemberCore) defined_names [name];
950 if (mc == null) {
951 defined_names.Add (name, symbol);
952 return true;
955 if (((mc.ModFlags | symbol.ModFlags) & Modifiers.COMPILER_GENERATED) != 0)
956 return true;
958 if (symbol.EnableOverloadChecks (mc))
959 return true;
961 InterfaceMemberBase im = mc as InterfaceMemberBase;
962 if (im != null && im.IsExplicitImpl)
963 return true;
965 Report.SymbolRelatedToPreviousError (mc);
966 if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (symbol is ClassOrStruct || symbol is Interface)) {
967 Error_MissingPartialModifier (symbol);
968 return false;
971 if (this is ModuleContainer) {
972 Report.Error (101, symbol.Location,
973 "The namespace `{0}' already contains a definition for `{1}'",
974 ((DeclSpace)symbol).NamespaceEntry.GetSignatureForError (), symbol.MemberName.Name);
975 } else if (symbol is TypeParameter) {
976 Report.Error (692, symbol.Location,
977 "Duplicate type parameter `{0}'", symbol.GetSignatureForError ());
978 } else {
979 Report.Error (102, symbol.Location,
980 "The type `{0}' already contains a definition for `{1}'",
981 GetSignatureForError (), symbol.MemberName.Name);
984 return false;
987 protected void RemoveFromContainer (string name)
989 defined_names.Remove (name);
992 /// <summary>
993 /// Returns the MemberCore associated with a given name in the declaration
994 /// space. It doesn't return method based symbols !!
995 /// </summary>
996 ///
997 public MemberCore GetDefinition (string name)
999 return (MemberCore)defined_names [name];
1002 public bool IsStaticClass {
1003 get { return (ModFlags & Modifiers.STATIC) != 0; }
1007 // root_types contains all the types. All TopLevel types
1008 // hence have a parent that points to `root_types', that is
1009 // why there is a non-obvious test down here.
1011 public bool IsTopLevel {
1012 get { return (Parent != null && Parent.Parent == null); }
1015 public virtual bool IsUnmanagedType ()
1017 return false;
1020 public virtual void CloseType ()
1022 if ((caching_flags & Flags.CloseTypeCreated) == 0){
1023 try {
1024 TypeBuilder.CreateType ();
1025 } catch {
1027 // The try/catch is needed because
1028 // nested enumerations fail to load when they
1029 // are defined.
1031 // Even if this is the right order (enumerations
1032 // declared after types).
1034 // Note that this still creates the type and
1035 // it is possible to save it
1037 caching_flags |= Flags.CloseTypeCreated;
1041 protected virtual TypeAttributes TypeAttr {
1042 get { return Module.DefaultCharSetType; }
1045 /// <remarks>
1046 /// Should be overriten by the appropriate declaration space
1047 /// </remarks>
1048 public abstract TypeBuilder DefineType ();
1050 protected void Error_MissingPartialModifier (MemberCore type)
1052 Report.Error (260, type.Location,
1053 "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists",
1054 type.GetSignatureForError ());
1057 public override void Emit ()
1059 if (type_params != null) {
1060 int offset = count_type_params - type_params.Length;
1061 for (int i = offset; i < type_params.Length; i++)
1062 CurrentTypeParameters [i - offset].Emit ();
1065 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
1066 PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (TypeBuilder);
1068 base.Emit ();
1071 public override string GetSignatureForError ()
1073 return MemberName.GetSignatureForError ();
1076 public bool CheckAccessLevel (Type check_type)
1078 Type tb = TypeBuilder;
1080 if (this is GenericMethod) {
1081 tb = Parent.TypeBuilder;
1083 // FIXME: Generic container does not work with nested generic
1084 // anonymous method stories
1085 if (TypeBuilder == null)
1086 return true;
1089 check_type = TypeManager.DropGenericTypeArguments (check_type);
1090 if (check_type == tb)
1091 return true;
1093 // TODO: When called from LocalUsingAliasEntry tb is null
1094 // because we are in RootDeclSpace
1095 if (tb == null)
1096 tb = typeof (RootDeclSpace);
1099 // Broken Microsoft runtime, return public for arrays, no matter what
1100 // the accessibility is for their underlying class, and they return
1101 // NonPublic visibility for pointers
1103 if (TypeManager.HasElementType (check_type))
1104 return CheckAccessLevel (TypeManager.GetElementType (check_type));
1106 if (TypeManager.IsGenericParameter (check_type))
1107 return true;
1109 TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
1111 switch (check_attr){
1112 case TypeAttributes.Public:
1113 return true;
1115 case TypeAttributes.NotPublic:
1116 return TypeManager.IsThisOrFriendAssembly (Module.Assembly, check_type.Assembly);
1118 case TypeAttributes.NestedPublic:
1119 return CheckAccessLevel (check_type.DeclaringType);
1121 case TypeAttributes.NestedPrivate:
1122 Type declaring = check_type.DeclaringType;
1123 return tb == declaring || TypeManager.IsNestedChildOf (tb, declaring);
1125 case TypeAttributes.NestedFamily:
1127 // Only accessible to methods in current type or any subtypes
1129 return FamilyAccessible (tb, check_type);
1131 case TypeAttributes.NestedFamANDAssem:
1132 return TypeManager.IsThisOrFriendAssembly (Module.Assembly, check_type.Assembly) &&
1133 FamilyAccessible (tb, check_type);
1135 case TypeAttributes.NestedFamORAssem:
1136 return FamilyAccessible (tb, check_type) ||
1137 TypeManager.IsThisOrFriendAssembly (Module.Assembly, check_type.Assembly);
1139 case TypeAttributes.NestedAssembly:
1140 return TypeManager.IsThisOrFriendAssembly (Module.Assembly, check_type.Assembly);
1143 throw new NotImplementedException (check_attr.ToString ());
1146 static bool FamilyAccessible (Type tb, Type check_type)
1148 Type declaring = check_type.DeclaringType;
1149 return TypeManager.IsNestedFamilyAccessible (tb, declaring);
1152 public bool IsBaseType (Type baseType)
1154 if (TypeManager.IsInterfaceType (baseType))
1155 throw new NotImplementedException ();
1157 Type type = TypeBuilder;
1158 while (type != null) {
1159 if (TypeManager.IsEqual (type, baseType))
1160 return true;
1162 type = type.BaseType;
1165 return false;
1168 private Type LookupNestedTypeInHierarchy (string name)
1170 Type t = null;
1171 // if the member cache has been created, lets use it.
1172 // the member cache is MUCH faster.
1173 if (MemberCache != null) {
1174 t = MemberCache.FindNestedType (name);
1175 if (t == null)
1176 return null;
1180 // FIXME: This hack is needed because member cache does not work
1181 // with nested base generic types, it does only type name copy and
1182 // not type construction
1185 // no member cache. Do it the hard way -- reflection
1186 for (Type current_type = TypeBuilder;
1187 current_type != null && current_type != TypeManager.object_type;
1188 current_type = current_type.BaseType) {
1190 Type ct = TypeManager.DropGenericTypeArguments (current_type);
1191 if (ct is TypeBuilder) {
1192 TypeContainer tc = ct == TypeBuilder
1193 ? PartialContainer : TypeManager.LookupTypeContainer (ct);
1194 if (tc != null)
1195 t = tc.FindNestedType (name);
1196 } else {
1197 t = TypeManager.GetNestedType (ct, name);
1200 if ((t == null) || !CheckAccessLevel (t))
1201 continue;
1203 if (!TypeManager.IsGenericType (current_type))
1204 return t;
1206 Type[] args = TypeManager.GetTypeArguments (current_type);
1207 Type[] targs = TypeManager.GetTypeArguments (t);
1208 for (int i = 0; i < args.Length; i++)
1209 targs [i] = TypeManager.TypeToCoreType (args [i]);
1211 return t.MakeGenericType (targs);
1214 return null;
1218 // Public function used to locate types.
1220 // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
1222 // Returns: Type or null if they type can not be found.
1224 public override FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
1226 if (Cache.Contains (name))
1227 return (FullNamedExpression) Cache [name];
1229 FullNamedExpression e = null;
1230 int errors = Report.Errors;
1232 TypeParameter[] tp = CurrentTypeParameters;
1233 if (tp != null) {
1234 TypeParameter tparam = TypeParameter.FindTypeParameter (tp, name);
1235 if (tparam != null)
1236 e = new TypeParameterExpr (tparam, Location.Null);
1239 if (e == null) {
1240 Type t = LookupNestedTypeInHierarchy (name);
1242 if (t != null)
1243 e = new TypeExpression (t, Location.Null);
1244 else if (Parent != null)
1245 e = Parent.LookupNamespaceOrType (name, loc, ignore_cs0104);
1246 else
1247 e = NamespaceEntry.LookupNamespaceOrType (name, loc, ignore_cs0104);
1250 if (errors == Report.Errors)
1251 Cache [name] = e;
1253 return e;
1256 /// <remarks>
1257 /// This function is broken and not what you're looking for. It should only
1258 /// be used while the type is still being created since it doesn't use the cache
1259 /// and relies on the filter doing the member name check.
1260 /// </remarks>
1262 // [Obsolete ("Only MemberCache approach should be used")]
1263 public virtual MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1264 MemberFilter filter, object criteria)
1266 throw new NotSupportedException ();
1269 /// <remarks>
1270 /// If we have a MemberCache, return it. This property may return null if the
1271 /// class doesn't have a member cache or while it's still being created.
1272 /// </remarks>
1273 public abstract MemberCache MemberCache {
1274 get;
1277 public virtual ModuleContainer Module {
1278 get { return Parent.Module; }
1281 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
1283 if (a.Type == pa.Required) {
1284 Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types");
1285 return;
1287 TypeBuilder.SetCustomAttribute (cb);
1290 TypeParameter[] initialize_type_params ()
1292 if (type_param_list != null)
1293 return type_param_list;
1295 DeclSpace the_parent = Parent;
1296 if (this is GenericMethod)
1297 the_parent = null;
1299 ArrayList list = new ArrayList ();
1300 if (the_parent != null && the_parent.IsGeneric) {
1301 // FIXME: move generics info out of DeclSpace
1302 TypeParameter[] parent_params = the_parent.TypeParameters;
1303 list.AddRange (parent_params);
1306 int count = type_params != null ? type_params.Length : 0;
1307 for (int i = 0; i < count; i++) {
1308 TypeParameter param = type_params [i];
1309 list.Add (param);
1310 if (Parent.CurrentTypeParameters != null) {
1311 foreach (TypeParameter tp in Parent.CurrentTypeParameters) {
1312 if (tp.Name != param.Name)
1313 continue;
1315 Report.SymbolRelatedToPreviousError (tp.Location, null);
1316 Report.Warning (693, 3, param.Location,
1317 "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
1318 param.Name, Parent.GetSignatureForError ());
1323 type_param_list = new TypeParameter [list.Count];
1324 list.CopyTo (type_param_list, 0);
1325 return type_param_list;
1328 public virtual void SetParameterInfo (ArrayList constraints_list)
1330 if (!is_generic) {
1331 if (constraints_list != null) {
1332 Report.Error (
1333 80, Location, "Constraints are not allowed " +
1334 "on non-generic declarations");
1337 return;
1340 TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
1341 type_params = new TypeParameter [names.Length];
1344 // Register all the names
1346 for (int i = 0; i < type_params.Length; i++) {
1347 TypeParameterName name = names [i];
1349 Constraints constraints = null;
1350 if (constraints_list != null) {
1351 int total = constraints_list.Count;
1352 for (int ii = 0; ii < total; ++ii) {
1353 Constraints constraints_at = (Constraints)constraints_list[ii];
1354 // TODO: it is used by iterators only
1355 if (constraints_at == null) {
1356 constraints_list.RemoveAt (ii);
1357 --total;
1358 continue;
1360 if (constraints_at.TypeParameter == name.Name) {
1361 constraints = constraints_at;
1362 constraints_list.RemoveAt(ii);
1363 break;
1368 Variance variance = name.Variance;
1369 if (name.Variance != Variance.None && !(this is Delegate || this is Interface)) {
1370 Report.Error (1960, name.Location, "Variant type parameters can only be used with interfaces and delegates");
1371 variance = Variance.None;
1374 type_params [i] = new TypeParameter (
1375 Parent, this, name.Name, constraints, name.OptAttributes, variance, Location);
1377 AddToContainer (type_params [i], name.Name);
1380 if (constraints_list != null && constraints_list.Count > 0) {
1381 foreach (Constraints constraint in constraints_list) {
1382 Report.Error(699, constraint.Location, "`{0}': A constraint references nonexistent type parameter `{1}'",
1383 GetSignatureForError (), constraint.TypeParameter);
1388 public TypeParameter[] TypeParameters {
1389 get {
1390 if (!IsGeneric)
1391 throw new InvalidOperationException ();
1392 if ((PartialContainer != null) && (PartialContainer != this))
1393 return PartialContainer.TypeParameters;
1394 if (type_param_list == null)
1395 initialize_type_params ();
1397 return type_param_list;
1401 public override Type CurrentType {
1402 get { return currentType != null ? currentType : TypeBuilder; }
1405 public override TypeContainer CurrentTypeDefinition {
1406 get { return PartialContainer; }
1409 public int CountTypeParameters {
1410 get {
1411 return count_type_params;
1415 // Used for error reporting only
1416 public virtual Type LookupAnyGeneric (string typeName)
1418 return NamespaceEntry.NS.LookForAnyGenericType (typeName);
1421 public override string[] ValidAttributeTargets {
1422 get { return attribute_targets; }
1425 protected override bool VerifyClsCompliance ()
1427 if (!base.VerifyClsCompliance ()) {
1428 return false;
1431 if (type_params != null) {
1432 foreach (TypeParameter tp in type_params) {
1433 if (tp.Constraints == null)
1434 continue;
1436 tp.Constraints.VerifyClsCompliance (Report);
1440 IDictionary cache = TypeManager.AllClsTopLevelTypes;
1441 if (cache == null)
1442 return true;
1444 string lcase = Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
1445 if (!cache.Contains (lcase)) {
1446 cache.Add (lcase, this);
1447 return true;
1450 object val = cache [lcase];
1451 if (val == null) {
1452 Type t = AttributeTester.GetImportedIgnoreCaseClsType (lcase);
1453 if (t == null)
1454 return true;
1455 Report.SymbolRelatedToPreviousError (t);
1457 else {
1458 Report.SymbolRelatedToPreviousError ((DeclSpace)val);
1461 Report.Warning (3005, 1, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
1462 return true;
1466 /// <summary>
1467 /// This is a readonly list of MemberInfo's.
1468 /// </summary>
1469 public class MemberList : IList {
1470 public readonly IList List;
1471 int count;
1473 /// <summary>
1474 /// Create a new MemberList from the given IList.
1475 /// </summary>
1476 public MemberList (IList list)
1478 if (list != null)
1479 this.List = list;
1480 else
1481 this.List = new ArrayList ();
1482 count = List.Count;
1485 /// <summary>
1486 /// Concatenate the ILists `first' and `second' to a new MemberList.
1487 /// </summary>
1488 public MemberList (IList first, IList second)
1490 ArrayList list = new ArrayList ();
1491 list.AddRange (first);
1492 list.AddRange (second);
1493 count = list.Count;
1494 List = list;
1497 public static readonly MemberList Empty = new MemberList (new ArrayList (0));
1499 /// <summary>
1500 /// Cast the MemberList into a MemberInfo[] array.
1501 /// </summary>
1502 /// <remarks>
1503 /// This is an expensive operation, only use it if it's really necessary.
1504 /// </remarks>
1505 public static explicit operator MemberInfo [] (MemberList list)
1507 Timer.StartTimer (TimerType.MiscTimer);
1508 MemberInfo [] result = new MemberInfo [list.Count];
1509 list.CopyTo (result, 0);
1510 Timer.StopTimer (TimerType.MiscTimer);
1511 return result;
1514 // ICollection
1516 public int Count {
1517 get {
1518 return count;
1522 public bool IsSynchronized {
1523 get {
1524 return List.IsSynchronized;
1528 public object SyncRoot {
1529 get {
1530 return List.SyncRoot;
1534 public void CopyTo (Array array, int index)
1536 List.CopyTo (array, index);
1539 // IEnumerable
1541 public IEnumerator GetEnumerator ()
1543 return List.GetEnumerator ();
1546 // IList
1548 public bool IsFixedSize {
1549 get {
1550 return true;
1554 public bool IsReadOnly {
1555 get {
1556 return true;
1560 object IList.this [int index] {
1561 get {
1562 return List [index];
1565 set {
1566 throw new NotSupportedException ();
1570 // FIXME: try to find out whether we can avoid the cast in this indexer.
1571 public MemberInfo this [int index] {
1572 get {
1573 return (MemberInfo) List [index];
1577 public int Add (object value)
1579 throw new NotSupportedException ();
1582 public void Clear ()
1584 throw new NotSupportedException ();
1587 public bool Contains (object value)
1589 return List.Contains (value);
1592 public int IndexOf (object value)
1594 return List.IndexOf (value);
1597 public void Insert (int index, object value)
1599 throw new NotSupportedException ();
1602 public void Remove (object value)
1604 throw new NotSupportedException ();
1607 public void RemoveAt (int index)
1609 throw new NotSupportedException ();
1613 /// <summary>
1614 /// This interface is used to get all members of a class when creating the
1615 /// member cache. It must be implemented by all DeclSpace derivatives which
1616 /// want to support the member cache and by TypeHandle to get caching of
1617 /// non-dynamic types.
1618 /// </summary>
1619 public interface IMemberContainer {
1620 /// <summary>
1621 /// The name of the IMemberContainer. This is only used for
1622 /// debugging purposes.
1623 /// </summary>
1624 string Name {
1625 get;
1628 /// <summary>
1629 /// The type of this IMemberContainer.
1630 /// </summary>
1631 Type Type {
1632 get;
1635 /// <summary>
1636 /// Returns the IMemberContainer of the base class or null if this
1637 /// is an interface or TypeManger.object_type.
1638 /// This is used when creating the member cache for a class to get all
1639 /// members from the base class.
1640 /// </summary>
1641 MemberCache BaseCache {
1642 get;
1645 /// <summary>
1646 /// Whether this is an interface.
1647 /// </summary>
1648 bool IsInterface {
1649 get;
1652 /// <summary>
1653 /// Returns all members of this class with the corresponding MemberTypes
1654 /// and BindingFlags.
1655 /// </summary>
1656 /// <remarks>
1657 /// When implementing this method, make sure not to return any inherited
1658 /// members and check the MemberTypes and BindingFlags properly.
1659 /// Unfortunately, System.Reflection is lame and doesn't provide a way to
1660 /// get the BindingFlags (static/non-static,public/non-public) in the
1661 /// MemberInfo class, but the cache needs this information. That's why
1662 /// this method is called multiple times with different BindingFlags.
1663 /// </remarks>
1664 MemberList GetMembers (MemberTypes mt, BindingFlags bf);
1667 /// <summary>
1668 /// The MemberCache is used by dynamic and non-dynamic types to speed up
1669 /// member lookups. It has a member name based hash table; it maps each member
1670 /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
1671 /// and the BindingFlags that were initially used to get it. The cache contains
1672 /// all members of the current class and all inherited members. If this cache is
1673 /// for an interface types, it also contains all inherited members.
1675 /// There are two ways to get a MemberCache:
1676 /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
1677 /// use the DeclSpace.MemberCache property.
1678 /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
1679 /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
1680 /// </summary>
1681 public class MemberCache {
1682 public readonly IMemberContainer Container;
1683 protected Hashtable member_hash;
1684 protected Hashtable method_hash;
1686 /// <summary>
1687 /// Create a new MemberCache for the given IMemberContainer `container'.
1688 /// </summary>
1689 public MemberCache (IMemberContainer container)
1691 this.Container = container;
1693 Timer.IncrementCounter (CounterType.MemberCache);
1694 Timer.StartTimer (TimerType.CacheInit);
1696 // If we have a base class (we have a base class unless we're
1697 // TypeManager.object_type), we deep-copy its MemberCache here.
1698 if (Container.BaseCache != null)
1699 member_hash = SetupCache (Container.BaseCache);
1700 else
1701 member_hash = new Hashtable ();
1703 // If this is neither a dynamic type nor an interface, create a special
1704 // method cache with all declared and inherited methods.
1705 Type type = container.Type;
1706 if (!(type is TypeBuilder) && !type.IsInterface &&
1707 // !(type.IsGenericType && (type.GetGenericTypeDefinition () is TypeBuilder)) &&
1708 !TypeManager.IsGenericType (type) && !TypeManager.IsGenericParameter (type) &&
1709 (Container.BaseCache == null || Container.BaseCache.method_hash != null)) {
1710 method_hash = new Hashtable ();
1711 AddMethods (type);
1714 // Add all members from the current class.
1715 AddMembers (Container);
1717 Timer.StopTimer (TimerType.CacheInit);
1720 public MemberCache (Type baseType, IMemberContainer container)
1722 this.Container = container;
1723 if (baseType == null)
1724 this.member_hash = new Hashtable ();
1725 else
1726 this.member_hash = SetupCache (TypeManager.LookupMemberCache (baseType));
1729 public MemberCache (Type[] ifaces)
1732 // The members of this cache all belong to other caches.
1733 // So, 'Container' will not be used.
1735 this.Container = null;
1737 member_hash = new Hashtable ();
1738 if (ifaces == null)
1739 return;
1741 foreach (Type itype in ifaces)
1742 AddCacheContents (TypeManager.LookupMemberCache (itype));
1745 public MemberCache (IMemberContainer container, Type base_class, Type[] ifaces)
1747 this.Container = container;
1749 // If we have a base class (we have a base class unless we're
1750 // TypeManager.object_type), we deep-copy its MemberCache here.
1751 if (Container.BaseCache != null)
1752 member_hash = SetupCache (Container.BaseCache);
1753 else
1754 member_hash = new Hashtable ();
1756 if (base_class != null)
1757 AddCacheContents (TypeManager.LookupMemberCache (base_class));
1758 if (ifaces != null) {
1759 foreach (Type itype in ifaces) {
1760 MemberCache cache = TypeManager.LookupMemberCache (itype);
1761 if (cache != null)
1762 AddCacheContents (cache);
1767 /// <summary>
1768 /// Bootstrap this member cache by doing a deep-copy of our base.
1769 /// </summary>
1770 static Hashtable SetupCache (MemberCache base_class)
1772 if (base_class == null)
1773 return new Hashtable ();
1775 Hashtable hash = new Hashtable (base_class.member_hash.Count);
1776 IDictionaryEnumerator it = base_class.member_hash.GetEnumerator ();
1777 while (it.MoveNext ()) {
1778 hash.Add (it.Key, ((ArrayList) it.Value).Clone ());
1781 return hash;
1785 // Converts ModFlags to BindingFlags
1787 static BindingFlags GetBindingFlags (int modifiers)
1789 BindingFlags bf;
1790 if ((modifiers & Modifiers.STATIC) != 0)
1791 bf = BindingFlags.Static;
1792 else
1793 bf = BindingFlags.Instance;
1795 if ((modifiers & Modifiers.PRIVATE) != 0)
1796 bf |= BindingFlags.NonPublic;
1797 else
1798 bf |= BindingFlags.Public;
1800 return bf;
1803 /// <summary>
1804 /// Add the contents of `cache' to the member_hash.
1805 /// </summary>
1806 void AddCacheContents (MemberCache cache)
1808 IDictionaryEnumerator it = cache.member_hash.GetEnumerator ();
1809 while (it.MoveNext ()) {
1810 ArrayList list = (ArrayList) member_hash [it.Key];
1811 if (list == null)
1812 member_hash [it.Key] = list = new ArrayList ();
1814 ArrayList entries = (ArrayList) it.Value;
1815 for (int i = entries.Count-1; i >= 0; i--) {
1816 CacheEntry entry = (CacheEntry) entries [i];
1818 if (entry.Container != cache.Container)
1819 break;
1820 list.Add (entry);
1825 /// <summary>
1826 /// Add all members from class `container' to the cache.
1827 /// </summary>
1828 void AddMembers (IMemberContainer container)
1830 // We need to call AddMembers() with a single member type at a time
1831 // to get the member type part of CacheEntry.EntryType right.
1832 if (!container.IsInterface) {
1833 AddMembers (MemberTypes.Constructor, container);
1834 AddMembers (MemberTypes.Field, container);
1836 AddMembers (MemberTypes.Method, container);
1837 AddMembers (MemberTypes.Property, container);
1838 AddMembers (MemberTypes.Event, container);
1839 // Nested types are returned by both Static and Instance searches.
1840 AddMembers (MemberTypes.NestedType,
1841 BindingFlags.Static | BindingFlags.Public, container);
1842 AddMembers (MemberTypes.NestedType,
1843 BindingFlags.Static | BindingFlags.NonPublic, container);
1846 void AddMembers (MemberTypes mt, IMemberContainer container)
1848 AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
1849 AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
1850 AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
1851 AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
1854 public void AddMember (MemberInfo mi, MemberCore mc)
1856 AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container, mi.Name, mi);
1859 public void AddGenericMember (MemberInfo mi, InterfaceMemberBase mc)
1861 AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container,
1862 MemberName.MakeName (mc.GetFullName (mc.MemberName), mc.MemberName.TypeArguments), mi);
1865 public void AddNestedType (DeclSpace type)
1867 AddMember (MemberTypes.NestedType, GetBindingFlags (type.ModFlags), (IMemberContainer) type.Parent,
1868 type.TypeBuilder.Name, type.TypeBuilder);
1871 public void AddInterface (MemberCache baseCache)
1873 if (baseCache.member_hash.Count > 0)
1874 AddCacheContents (baseCache);
1877 void AddMember (MemberTypes mt, BindingFlags bf, IMemberContainer container,
1878 string name, MemberInfo member)
1880 // We use a name-based hash table of ArrayList's.
1881 ArrayList list = (ArrayList) member_hash [name];
1882 if (list == null) {
1883 list = new ArrayList (1);
1884 member_hash.Add (name, list);
1887 // When this method is called for the current class, the list will
1888 // already contain all inherited members from our base classes.
1889 // We cannot add new members in front of the list since this'd be an
1890 // expensive operation, that's why the list is sorted in reverse order
1891 // (ie. members from the current class are coming last).
1892 list.Add (new CacheEntry (container, member, mt, bf));
1895 /// <summary>
1896 /// Add all members from class `container' with the requested MemberTypes and
1897 /// BindingFlags to the cache. This method is called multiple times with different
1898 /// MemberTypes and BindingFlags.
1899 /// </summary>
1900 void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
1902 MemberList members = container.GetMembers (mt, bf);
1904 foreach (MemberInfo member in members) {
1905 string name = member.Name;
1907 AddMember (mt, bf, container, name, member);
1909 if (member is MethodInfo) {
1910 string gname = TypeManager.GetMethodName ((MethodInfo) member);
1911 if (gname != name)
1912 AddMember (mt, bf, container, gname, member);
1917 /// <summary>
1918 /// Add all declared and inherited methods from class `type' to the method cache.
1919 /// </summary>
1920 void AddMethods (Type type)
1922 AddMethods (BindingFlags.Static | BindingFlags.Public |
1923 BindingFlags.FlattenHierarchy, type);
1924 AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
1925 BindingFlags.FlattenHierarchy, type);
1926 AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
1927 AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
1930 static ArrayList overrides = new ArrayList ();
1932 void AddMethods (BindingFlags bf, Type type)
1934 MethodBase [] members = type.GetMethods (bf);
1936 Array.Reverse (members);
1938 foreach (MethodBase member in members) {
1939 string name = member.Name;
1941 // We use a name-based hash table of ArrayList's.
1942 ArrayList list = (ArrayList) method_hash [name];
1943 if (list == null) {
1944 list = new ArrayList (1);
1945 method_hash.Add (name, list);
1948 MethodInfo curr = (MethodInfo) member;
1949 while (curr.IsVirtual && (curr.Attributes & MethodAttributes.NewSlot) == 0) {
1950 MethodInfo base_method = curr.GetBaseDefinition ();
1952 if (base_method == curr)
1953 // Not every virtual function needs to have a NewSlot flag.
1954 break;
1956 overrides.Add (curr);
1957 list.Add (new CacheEntry (null, base_method, MemberTypes.Method, bf));
1958 curr = base_method;
1961 if (overrides.Count > 0) {
1962 for (int i = 0; i < overrides.Count; ++i)
1963 TypeManager.RegisterOverride ((MethodBase) overrides [i], curr);
1964 overrides.Clear ();
1967 // Unfortunately, the elements returned by Type.GetMethods() aren't
1968 // sorted so we need to do this check for every member.
1969 BindingFlags new_bf = bf;
1970 if (member.DeclaringType == type)
1971 new_bf |= BindingFlags.DeclaredOnly;
1973 list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
1977 /// <summary>
1978 /// Compute and return a appropriate `EntryType' magic number for the given
1979 /// MemberTypes and BindingFlags.
1980 /// </summary>
1981 protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
1983 EntryType type = EntryType.None;
1985 if ((mt & MemberTypes.Constructor) != 0)
1986 type |= EntryType.Constructor;
1987 if ((mt & MemberTypes.Event) != 0)
1988 type |= EntryType.Event;
1989 if ((mt & MemberTypes.Field) != 0)
1990 type |= EntryType.Field;
1991 if ((mt & MemberTypes.Method) != 0)
1992 type |= EntryType.Method;
1993 if ((mt & MemberTypes.Property) != 0)
1994 type |= EntryType.Property;
1995 // Nested types are returned by static and instance searches.
1996 if ((mt & MemberTypes.NestedType) != 0)
1997 type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
1999 if ((bf & BindingFlags.Instance) != 0)
2000 type |= EntryType.Instance;
2001 if ((bf & BindingFlags.Static) != 0)
2002 type |= EntryType.Static;
2003 if ((bf & BindingFlags.Public) != 0)
2004 type |= EntryType.Public;
2005 if ((bf & BindingFlags.NonPublic) != 0)
2006 type |= EntryType.NonPublic;
2007 if ((bf & BindingFlags.DeclaredOnly) != 0)
2008 type |= EntryType.Declared;
2010 return type;
2013 /// <summary>
2014 /// The `MemberTypes' enumeration type is a [Flags] type which means that it may
2015 /// denote multiple member types. Returns true if the given flags value denotes a
2016 /// single member types.
2017 /// </summary>
2018 public static bool IsSingleMemberType (MemberTypes mt)
2020 switch (mt) {
2021 case MemberTypes.Constructor:
2022 case MemberTypes.Event:
2023 case MemberTypes.Field:
2024 case MemberTypes.Method:
2025 case MemberTypes.Property:
2026 case MemberTypes.NestedType:
2027 return true;
2029 default:
2030 return false;
2034 /// <summary>
2035 /// We encode the MemberTypes and BindingFlags of each members in a "magic"
2036 /// number to speed up the searching process.
2037 /// </summary>
2038 [Flags]
2039 protected enum EntryType {
2040 None = 0x000,
2042 Instance = 0x001,
2043 Static = 0x002,
2044 MaskStatic = Instance|Static,
2046 Public = 0x004,
2047 NonPublic = 0x008,
2048 MaskProtection = Public|NonPublic,
2050 Declared = 0x010,
2052 Constructor = 0x020,
2053 Event = 0x040,
2054 Field = 0x080,
2055 Method = 0x100,
2056 Property = 0x200,
2057 NestedType = 0x400,
2059 NotExtensionMethod = 0x800,
2061 MaskType = Constructor|Event|Field|Method|Property|NestedType
2064 protected class CacheEntry {
2065 public readonly IMemberContainer Container;
2066 public EntryType EntryType;
2067 public readonly MemberInfo Member;
2069 public CacheEntry (IMemberContainer container, MemberInfo member,
2070 MemberTypes mt, BindingFlags bf)
2072 this.Container = container;
2073 this.Member = member;
2074 this.EntryType = GetEntryType (mt, bf);
2077 public override string ToString ()
2079 return String.Format ("CacheEntry ({0}:{1}:{2})", Container.Name,
2080 EntryType, Member);
2084 /// <summary>
2085 /// This is called each time we're walking up one level in the class hierarchy
2086 /// and checks whether we can abort the search since we've already found what
2087 /// we were looking for.
2088 /// </summary>
2089 protected bool DoneSearching (ArrayList list)
2092 // We've found exactly one member in the current class and it's not
2093 // a method or constructor.
2095 if (list.Count == 1 && !(list [0] is MethodBase))
2096 return true;
2099 // Multiple properties: we query those just to find out the indexer
2100 // name
2102 if ((list.Count > 0) && (list [0] is PropertyInfo))
2103 return true;
2105 return false;
2108 /// <summary>
2109 /// Looks up members with name `name'. If you provide an optional
2110 /// filter function, it'll only be called with members matching the
2111 /// requested member name.
2113 /// This method will try to use the cache to do the lookup if possible.
2115 /// Unlike other FindMembers implementations, this method will always
2116 /// check all inherited members - even when called on an interface type.
2118 /// If you know that you're only looking for methods, you should use
2119 /// MemberTypes.Method alone since this speeds up the lookup a bit.
2120 /// When doing a method-only search, it'll try to use a special method
2121 /// cache (unless it's a dynamic type or an interface) and the returned
2122 /// MemberInfo's will have the correct ReflectedType for inherited methods.
2123 /// The lookup process will automatically restart itself in method-only
2124 /// search mode if it discovers that it's about to return methods.
2125 /// </summary>
2126 ArrayList global = new ArrayList ();
2127 bool using_global = false;
2129 static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
2131 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
2132 MemberFilter filter, object criteria)
2134 if (using_global)
2135 throw new Exception ();
2137 bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
2138 bool method_search = mt == MemberTypes.Method;
2139 // If we have a method cache and we aren't already doing a method-only search,
2140 // then we restart a method search if the first match is a method.
2141 bool do_method_search = !method_search && (method_hash != null);
2143 ArrayList applicable;
2145 // If this is a method-only search, we try to use the method cache if
2146 // possible; a lookup in the method cache will return a MemberInfo with
2147 // the correct ReflectedType for inherited methods.
2149 if (method_search && (method_hash != null))
2150 applicable = (ArrayList) method_hash [name];
2151 else
2152 applicable = (ArrayList) member_hash [name];
2154 if (applicable == null)
2155 return emptyMemberInfo;
2158 // 32 slots gives 53 rss/54 size
2159 // 2/4 slots gives 55 rss
2161 // Strange: from 25,000 calls, only 1,800
2162 // are above 2. Why does this impact it?
2164 global.Clear ();
2165 using_global = true;
2167 Timer.StartTimer (TimerType.CachedLookup);
2169 EntryType type = GetEntryType (mt, bf);
2171 IMemberContainer current = Container;
2173 bool do_interface_search = current.IsInterface;
2175 // `applicable' is a list of all members with the given member name `name'
2176 // in the current class and all its base classes. The list is sorted in
2177 // reverse order due to the way how the cache is initialy created (to speed
2178 // things up, we're doing a deep-copy of our base).
2180 for (int i = applicable.Count-1; i >= 0; i--) {
2181 CacheEntry entry = (CacheEntry) applicable [i];
2183 // This happens each time we're walking one level up in the class
2184 // hierarchy. If we're doing a DeclaredOnly search, we must abort
2185 // the first time this happens (this may already happen in the first
2186 // iteration of this loop if there are no members with the name we're
2187 // looking for in the current class).
2188 if (entry.Container != current) {
2189 if (declared_only)
2190 break;
2192 if (!do_interface_search && DoneSearching (global))
2193 break;
2195 current = entry.Container;
2198 // Is the member of the correct type ?
2199 if ((entry.EntryType & type & EntryType.MaskType) == 0)
2200 continue;
2202 // Is the member static/non-static ?
2203 if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
2204 continue;
2206 // Apply the filter to it.
2207 if (filter (entry.Member, criteria)) {
2208 if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) {
2209 do_method_search = false;
2212 // Because interfaces support multiple inheritance we have to be sure that
2213 // base member is from same interface, so only top level member will be returned
2214 if (do_interface_search && global.Count > 0) {
2215 bool member_already_exists = false;
2217 foreach (MemberInfo mi in global) {
2218 if (mi is MethodBase)
2219 continue;
2221 if (IsInterfaceBaseInterface (TypeManager.GetInterfaces (mi.DeclaringType), entry.Member.DeclaringType)) {
2222 member_already_exists = true;
2223 break;
2226 if (member_already_exists)
2227 continue;
2230 global.Add (entry.Member);
2234 Timer.StopTimer (TimerType.CachedLookup);
2236 // If we have a method cache and we aren't already doing a method-only
2237 // search, we restart in method-only search mode if the first match is
2238 // a method. This ensures that we return a MemberInfo with the correct
2239 // ReflectedType for inherited methods.
2240 if (do_method_search && (global.Count > 0)){
2241 using_global = false;
2243 return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
2246 using_global = false;
2247 MemberInfo [] copy = new MemberInfo [global.Count];
2248 global.CopyTo (copy);
2249 return copy;
2252 /// <summary>
2253 /// Returns true if iterface exists in any base interfaces (ifaces)
2254 /// </summary>
2255 static bool IsInterfaceBaseInterface (Type[] ifaces, Type ifaceToFind)
2257 foreach (Type iface in ifaces) {
2258 if (iface == ifaceToFind)
2259 return true;
2261 Type[] base_ifaces = TypeManager.GetInterfaces (iface);
2262 if (base_ifaces.Length > 0 && IsInterfaceBaseInterface (base_ifaces, ifaceToFind))
2263 return true;
2265 return false;
2268 // find the nested type @name in @this.
2269 public Type FindNestedType (string name)
2271 ArrayList applicable = (ArrayList) member_hash [name];
2272 if (applicable == null)
2273 return null;
2275 for (int i = applicable.Count-1; i >= 0; i--) {
2276 CacheEntry entry = (CacheEntry) applicable [i];
2277 if ((entry.EntryType & EntryType.NestedType & EntryType.MaskType) != 0)
2278 return (Type) entry.Member;
2281 return null;
2284 public MemberInfo FindBaseEvent (Type invocation_type, string name)
2286 ArrayList applicable = (ArrayList) member_hash [name];
2287 if (applicable == null)
2288 return null;
2291 // Walk the chain of events, starting from the top.
2293 for (int i = applicable.Count - 1; i >= 0; i--)
2295 CacheEntry entry = (CacheEntry) applicable [i];
2296 if ((entry.EntryType & EntryType.Event) == 0)
2297 continue;
2299 EventInfo ei = (EventInfo)entry.Member;
2300 return ei.GetAddMethod (true);
2303 return null;
2307 // Looks for extension methods with defined name and extension type
2309 public ArrayList FindExtensionMethods (Assembly thisAssembly, Type extensionType, string name, bool publicOnly)
2311 ArrayList entries;
2312 if (method_hash != null)
2313 entries = (ArrayList)method_hash [name];
2314 else
2315 entries = (ArrayList)member_hash [name];
2317 if (entries == null)
2318 return null;
2320 EntryType entry_type = EntryType.Static | EntryType.Method | EntryType.NotExtensionMethod;
2321 EntryType found_entry_type = entry_type & ~EntryType.NotExtensionMethod;
2323 ArrayList candidates = null;
2324 foreach (CacheEntry entry in entries) {
2325 if ((entry.EntryType & entry_type) == found_entry_type) {
2326 MethodBase mb = (MethodBase)entry.Member;
2328 // Simple accessibility check
2329 if ((entry.EntryType & EntryType.Public) == 0 && publicOnly) {
2330 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2331 if (ma != MethodAttributes.Assembly && ma != MethodAttributes.FamORAssem)
2332 continue;
2334 if (!TypeManager.IsThisOrFriendAssembly (thisAssembly, mb.DeclaringType.Assembly))
2335 continue;
2338 IMethodData md = TypeManager.GetMethod (mb);
2339 AParametersCollection pd = md == null ?
2340 TypeManager.GetParameterData (mb) : md.ParameterInfo;
2342 Type ex_type = pd.ExtensionMethodType;
2343 if (ex_type == null) {
2344 entry.EntryType |= EntryType.NotExtensionMethod;
2345 continue;
2348 //if (implicit conversion between ex_type and extensionType exist) {
2349 if (candidates == null)
2350 candidates = new ArrayList (2);
2351 candidates.Add (mb);
2356 return candidates;
2360 // This finds the method or property for us to override. invocation_type is the type where
2361 // the override is going to be declared, name is the name of the method/property, and
2362 // param_types is the parameters, if any to the method or property
2364 // Because the MemberCache holds members from this class and all the base classes,
2365 // we can avoid tons of reflection stuff.
2367 public MemberInfo FindMemberToOverride (Type invocation_type, string name, AParametersCollection parameters, GenericMethod generic_method, bool is_property)
2369 ArrayList applicable;
2370 if (method_hash != null && !is_property)
2371 applicable = (ArrayList) method_hash [name];
2372 else
2373 applicable = (ArrayList) member_hash [name];
2375 if (applicable == null)
2376 return null;
2378 // Walk the chain of methods, starting from the top.
2380 for (int i = applicable.Count - 1; i >= 0; i--) {
2381 CacheEntry entry = (CacheEntry) applicable [i];
2383 if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
2384 continue;
2386 PropertyInfo pi = null;
2387 MethodInfo mi = null;
2388 FieldInfo fi = null;
2389 AParametersCollection cmp_attrs;
2391 if (is_property) {
2392 if ((entry.EntryType & EntryType.Field) != 0) {
2393 fi = (FieldInfo)entry.Member;
2394 cmp_attrs = ParametersCompiled.EmptyReadOnlyParameters;
2395 } else {
2396 pi = (PropertyInfo) entry.Member;
2397 cmp_attrs = TypeManager.GetParameterData (pi);
2399 } else {
2400 mi = (MethodInfo) entry.Member;
2401 cmp_attrs = TypeManager.GetParameterData (mi);
2404 if (fi != null) {
2405 // TODO: Almost duplicate !
2406 // Check visibility
2407 switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
2408 case FieldAttributes.PrivateScope:
2409 continue;
2410 case FieldAttributes.Private:
2412 // A private method is Ok if we are a nested subtype.
2413 // The spec actually is not very clear about this, see bug 52458.
2415 if (!invocation_type.Equals (entry.Container.Type) &&
2416 !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
2417 continue;
2418 break;
2419 case FieldAttributes.FamANDAssem:
2420 case FieldAttributes.Assembly:
2422 // Check for assembly methods
2424 if (fi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
2425 continue;
2426 break;
2428 return entry.Member;
2432 // Check the arguments
2434 if (cmp_attrs.Count != parameters.Count)
2435 continue;
2437 int j;
2438 for (j = 0; j < cmp_attrs.Count; ++j) {
2440 // LAMESPEC: No idea why `params' modifier is ignored
2442 if ((parameters.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS) !=
2443 (cmp_attrs.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS))
2444 break;
2446 if (!TypeManager.IsEqual (parameters.Types [j], cmp_attrs.Types [j]))
2447 break;
2450 if (j < cmp_attrs.Count)
2451 continue;
2454 // check generic arguments for methods
2456 if (mi != null) {
2457 Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi);
2458 if (generic_method == null && cmpGenArgs != null && cmpGenArgs.Length != 0)
2459 continue;
2460 if (generic_method != null && cmpGenArgs != null && cmpGenArgs.Length != generic_method.TypeParameters.Length)
2461 continue;
2465 // get one of the methods because this has the visibility info.
2467 if (is_property) {
2468 mi = pi.GetGetMethod (true);
2469 if (mi == null)
2470 mi = pi.GetSetMethod (true);
2474 // Check visibility
2476 switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
2477 case MethodAttributes.PrivateScope:
2478 continue;
2479 case MethodAttributes.Private:
2481 // A private method is Ok if we are a nested subtype.
2482 // The spec actually is not very clear about this, see bug 52458.
2484 if (!invocation_type.Equals (entry.Container.Type) &&
2485 !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
2486 continue;
2487 break;
2488 case MethodAttributes.FamANDAssem:
2489 case MethodAttributes.Assembly:
2491 // Check for assembly methods
2493 if (!TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly))
2494 continue;
2495 break;
2497 return entry.Member;
2500 return null;
2503 /// <summary>
2504 /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
2505 /// We handle two cases. The first is for types without parameters (events, field, properties).
2506 /// The second are methods, indexers and this is why ignore_complex_types is here.
2507 /// The latest param is temporary hack. See DoDefineMembers method for more info.
2508 /// </summary>
2509 public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
2511 ArrayList applicable = null;
2513 if (method_hash != null)
2514 applicable = (ArrayList) method_hash [name];
2516 if (applicable != null) {
2517 for (int i = applicable.Count - 1; i >= 0; i--) {
2518 CacheEntry entry = (CacheEntry) applicable [i];
2519 if ((entry.EntryType & EntryType.Public) != 0)
2520 return entry.Member;
2524 if (member_hash == null)
2525 return null;
2526 applicable = (ArrayList) member_hash [name];
2528 if (applicable != null) {
2529 for (int i = applicable.Count - 1; i >= 0; i--) {
2530 CacheEntry entry = (CacheEntry) applicable [i];
2531 if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
2532 if (ignore_complex_types) {
2533 if ((entry.EntryType & EntryType.Method) != 0)
2534 continue;
2536 // Does exist easier way how to detect indexer ?
2537 if ((entry.EntryType & EntryType.Property) != 0) {
2538 AParametersCollection arg_types = TypeManager.GetParameterData ((PropertyInfo)entry.Member);
2539 if (arg_types.Count > 0)
2540 continue;
2543 return entry.Member;
2547 return null;
2550 Hashtable locase_table;
2552 /// <summary>
2553 /// Builds low-case table for CLS Compliance test
2554 /// </summary>
2555 public Hashtable GetPublicMembers ()
2557 if (locase_table != null)
2558 return locase_table;
2560 locase_table = new Hashtable ();
2561 foreach (DictionaryEntry entry in member_hash) {
2562 ArrayList members = (ArrayList)entry.Value;
2563 for (int ii = 0; ii < members.Count; ++ii) {
2564 CacheEntry member_entry = (CacheEntry) members [ii];
2566 if ((member_entry.EntryType & EntryType.Public) == 0)
2567 continue;
2569 // TODO: Does anyone know easier way how to detect that member is internal ?
2570 switch (member_entry.EntryType & EntryType.MaskType) {
2571 case EntryType.Constructor:
2572 continue;
2574 case EntryType.Field:
2575 if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
2576 continue;
2577 break;
2579 case EntryType.Method:
2580 if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2581 continue;
2582 break;
2584 case EntryType.Property:
2585 PropertyInfo pi = (PropertyInfo)member_entry.Member;
2586 if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
2587 continue;
2588 break;
2590 case EntryType.Event:
2591 EventInfo ei = (EventInfo)member_entry.Member;
2592 MethodInfo mi = ei.GetAddMethod ();
2593 if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2594 continue;
2595 break;
2597 string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
2598 locase_table [lcase] = member_entry.Member;
2599 break;
2602 return locase_table;
2605 public Hashtable Members {
2606 get {
2607 return member_hash;
2611 /// <summary>
2612 /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
2613 /// </summary>
2614 ///
2615 // TODO: refactor as method is always 'this'
2616 public static void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder, Report Report)
2618 EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
2620 for (int i = 0; i < al.Count; ++i) {
2621 MemberCache.CacheEntry entry = (MemberCache.CacheEntry) al [i];
2623 // skip itself
2624 if (entry.Member == this_builder)
2625 continue;
2627 if ((entry.EntryType & tested_type) != tested_type)
2628 continue;
2630 MethodBase method_to_compare = (MethodBase)entry.Member;
2631 AttributeTester.Result result = AttributeTester.AreOverloadedMethodParamsClsCompliant (
2632 method.Parameters, TypeManager.GetParameterData (method_to_compare));
2634 if (result == AttributeTester.Result.Ok)
2635 continue;
2637 IMethodData md = TypeManager.GetMethod (method_to_compare);
2639 // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
2640 // However it is exactly what csc does.
2641 if (md != null && !md.IsClsComplianceRequired ())
2642 continue;
2644 Report.SymbolRelatedToPreviousError (entry.Member);
2645 switch (result) {
2646 case AttributeTester.Result.RefOutArrayError:
2647 Report.Warning (3006, 1, method.Location,
2648 "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
2649 method.GetSignatureForError ());
2650 continue;
2651 case AttributeTester.Result.ArrayArrayError:
2652 Report.Warning (3007, 1, method.Location,
2653 "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
2654 method.GetSignatureForError ());
2655 continue;
2658 throw new NotImplementedException (result.ToString ());
2662 public bool CheckExistingMembersOverloads (MemberCore member, string name, ParametersCompiled parameters, Report Report)
2664 ArrayList entries = (ArrayList)member_hash [name];
2665 if (entries == null)
2666 return true;
2668 int method_param_count = parameters.Count;
2669 for (int i = entries.Count - 1; i >= 0; --i) {
2670 CacheEntry ce = (CacheEntry) entries [i];
2672 if (ce.Container != member.Parent.PartialContainer)
2673 return true;
2675 Type [] p_types;
2676 AParametersCollection pd;
2677 if ((ce.EntryType & EntryType.Property) != 0) {
2678 pd = TypeManager.GetParameterData ((PropertyInfo) ce.Member);
2679 p_types = pd.Types;
2680 } else {
2681 MethodBase mb = (MethodBase) ce.Member;
2683 // TODO: This is more like a hack, because we are adding generic methods
2684 // twice with and without arity name
2685 if (TypeManager.IsGenericMethod (mb) && !member.MemberName.IsGeneric)
2686 continue;
2688 pd = TypeManager.GetParameterData (mb);
2689 p_types = pd.Types;
2692 if (p_types.Length != method_param_count)
2693 continue;
2695 if (method_param_count > 0) {
2696 int ii = method_param_count - 1;
2697 Type type_a, type_b;
2698 do {
2699 type_a = parameters.Types [ii];
2700 type_b = p_types [ii];
2702 if (TypeManager.IsGenericParameter (type_a) && type_a.DeclaringMethod != null)
2703 type_a = typeof (TypeParameter);
2705 if (TypeManager.IsGenericParameter (type_b) && type_b.DeclaringMethod != null)
2706 type_b = typeof (TypeParameter);
2708 if ((pd.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF) !=
2709 (parameters.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF))
2710 break;
2712 } while (TypeManager.IsEqual (type_a, type_b) && ii-- != 0);
2714 if (ii >= 0)
2715 continue;
2718 // Operators can differ in return type only
2720 if (member is Operator) {
2721 Operator op = TypeManager.GetMethod ((MethodBase) ce.Member) as Operator;
2722 if (op != null && op.ReturnType != ((Operator) member).ReturnType)
2723 continue;
2727 // Report difference in parameter modifiers only
2729 if (pd != null && member is MethodCore) {
2730 ii = method_param_count;
2731 while (ii-- != 0 && parameters.FixedParameters [ii].ModFlags == pd.FixedParameters [ii].ModFlags &&
2732 parameters.ExtensionMethodType == pd.ExtensionMethodType);
2734 if (ii >= 0) {
2735 MethodCore mc = TypeManager.GetMethod ((MethodBase) ce.Member) as MethodCore;
2736 Report.SymbolRelatedToPreviousError (ce.Member);
2737 if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.ModFlags & Modifiers.PARTIAL) != 0) {
2738 if (parameters.HasParams || pd.HasParams) {
2739 Report.Error (758, member.Location,
2740 "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
2741 } else {
2742 Report.Error (755, member.Location,
2743 "A partial method declaration and partial method implementation must be both an extension method or neither");
2745 } else {
2746 if (member is Constructor) {
2747 Report.Error (851, member.Location,
2748 "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
2749 member.GetSignatureForError ());
2750 } else {
2751 Report.Error (663, member.Location,
2752 "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
2753 member.GetSignatureForError ());
2756 return false;
2761 if ((ce.EntryType & EntryType.Method) != 0) {
2762 Method method_a = member as Method;
2763 Method method_b = TypeManager.GetMethod ((MethodBase) ce.Member) as Method;
2764 if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
2765 const int partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
2766 if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
2767 if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
2768 method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
2769 if (method_a.IsPartialImplementation) {
2770 method_a.SetPartialDefinition (method_b);
2771 entries.RemoveAt (i);
2772 } else {
2773 method_b.SetPartialDefinition (method_a);
2775 continue;
2778 if ((method_a.ModFlags & Modifiers.STATIC) != (method_b.ModFlags & Modifiers.STATIC)) {
2779 Report.SymbolRelatedToPreviousError (ce.Member);
2780 Report.Error (763, member.Location,
2781 "A partial method declaration and partial method implementation must be both `static' or neither");
2784 Report.SymbolRelatedToPreviousError (ce.Member);
2785 Report.Error (764, member.Location,
2786 "A partial method declaration and partial method implementation must be both `unsafe' or neither");
2787 return false;
2790 Report.SymbolRelatedToPreviousError (ce.Member);
2791 if (method_a.IsPartialDefinition) {
2792 Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
2793 member.GetSignatureForError ());
2796 Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
2797 member.GetSignatureForError ());
2798 return false;
2801 Report.SymbolRelatedToPreviousError (ce.Member);
2802 IMethodData duplicate_member = TypeManager.GetMethod ((MethodBase) ce.Member);
2803 if (member is Operator && duplicate_member is Operator) {
2804 Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
2805 member.Parent.GetSignatureForError ());
2806 return false;
2809 bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
2810 bool is_reserved_b = duplicate_member is AbstractPropertyEventMethod || duplicate_member is Operator;
2812 if (is_reserved_a || is_reserved_b) {
2813 Report.Error (82, member.Location, "A member `{0}' is already reserved",
2814 is_reserved_a ?
2815 TypeManager.GetFullNameSignature (ce.Member) :
2816 member.GetSignatureForError ());
2817 return false;
2819 } else {
2820 Report.SymbolRelatedToPreviousError (ce.Member);
2823 Report.Error (111, member.Location,
2824 "A member `{0}' is already defined. Rename this member or use different parameter types",
2825 member.GetSignatureForError ());
2826 return false;
2829 return true;