2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2004-2008 Novell, Inc
16 using System
.Collections
;
17 using System
.Globalization
;
18 using System
.Reflection
.Emit
;
19 using System
.Reflection
;
22 using XmlElement
= System
.Object
;
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 ("");
43 private MemberName (MemberName left
, string name
, bool is_double_colon
,
48 this.is_double_colon
= is_double_colon
;
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
)
64 public MemberName (string name
, Location loc
)
65 : this (null, name
, false, loc
)
68 public MemberName (string name
, TypeArguments args
, Location loc
)
69 : this (null, name
, false, args
, loc
)
72 public MemberName (MemberName left
, string name
)
73 : this (left
, name
, left
!= null ? left
.Location
: Location
.Null
)
76 public MemberName (MemberName left
, string name
, Location loc
)
77 : this (left
, name
, false, loc
)
80 public MemberName (MemberName left
, string name
, TypeArguments args
, Location loc
)
81 : this (left
, name
, false, args
, loc
)
84 public MemberName (string alias, string name
, TypeArguments args
, Location loc
)
85 : this (new MemberName (alias, loc
), name
, true, args
, loc
)
88 public MemberName (MemberName left
, MemberName right
)
89 : this (left
, right
, right
.Location
)
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
);
101 public string GetName ()
103 return GetName (false);
106 public bool IsGeneric
{
108 if (TypeArguments
!= null)
110 else if (Left
!= null)
111 return Left
.IsGeneric
;
117 public string GetName (bool is_generic
)
119 string name
= is_generic
? Basename
: Name
;
121 return Left
.GetName (is_generic
) + (is_double_colon
? "::" : ".") + name
;
126 public ATypeNameExpression
GetTypeExpression ()
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
{
153 if (TypeArguments
!= null)
154 return MakeName (Name
, TypeArguments
);
159 public string GetSignatureForError ()
161 string append
= TypeArguments
== null ? "" : "<" + TypeArguments
.GetSignatureForError () + ">";
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
)
177 if (other
== null || Name
!= other
.Name
)
179 if (is_double_colon
!= other
.is_double_colon
)
182 if ((TypeArguments
!= null) &&
183 (other
.TypeArguments
== null || TypeArguments
.Count
!= other
.TypeArguments
.Count
))
186 if ((TypeArguments
== null) && (other
.TypeArguments
!= 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 ();
203 if (TypeArguments
!= null)
204 hash ^
= TypeArguments
.Count
<< 5;
206 return hash
& 0x7FFFFFFF;
209 public int CountTypeArguments
{
211 if (TypeArguments
!= null)
212 return TypeArguments
.Count
;
213 else if (Left
!= null)
214 return Left
.CountTypeArguments
;
220 public static string MakeName (string name
, TypeArguments args
)
225 return name
+ "`" + args
.Count
;
228 public static string MakeName (string name
, int count
)
230 return name
+ "`" + count
;
235 /// Base representation for members. This is used to keep track
236 /// of Name, Location and Modifier flags, and handling Attributes.
238 public abstract class MemberCore
: Attributable
, IMemberContext
{
243 protected string cached_name
;
244 // TODO: Remove in favor of MemberName
247 if (cached_name
== null)
248 cached_name
= MemberName
.GetName (!(this is GenericMethod
) && !(this is Method
));
253 // Is not readonly because of IndexerName attribute
254 private MemberName member_name
;
255 public MemberName MemberName
{
256 get { return member_name; }
260 /// Modifier flags that the user specified in the source code
262 private int mod_flags
;
263 public int ModFlags
{
266 if ((value & Modifiers
.COMPILER_GENERATED
) != 0)
267 caching_flags
= Flags
.IsUsed
| Flags
.IsAssigned
;
274 public /*readonly*/ DeclSpace Parent
;
277 /// Location where this declaration happens
279 public Location Location
{
280 get { return member_name.Location; }
284 /// XML documentation comment
286 protected string comment
;
289 /// Represents header string for documentation comment
290 /// for each member types.
292 public abstract string DocCommentHeader { get; }
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
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
315 /// MemberCore flags at first detected then cached
317 internal Flags caching_flags
;
319 public MemberCore (DeclSpace parent
, MemberName name
, Attributes attrs
)
321 this.Parent
= parent
;
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
;
333 protected bool CheckAbstractAndExtern (bool has_block
)
335 if (Parent
.PartialContainer
.Kind
== Kind
.Interface
)
339 if ((ModFlags
& Modifiers
.EXTERN
) != 0) {
340 Report
.Error (179, Location
, "`{0}' cannot declare a body because it is marked extern",
341 GetSignatureForError ());
345 if ((ModFlags
& Modifiers
.ABSTRACT
) != 0) {
346 Report
.Error (500, Location
, "`{0}' cannot declare a body because it is marked abstract",
347 GetSignatureForError ());
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
)
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 ());
365 Report
.Error (501, Location
, "`{0}' must have a body because it is not marked abstract, extern, or partial",
366 GetSignatureForError ());
374 protected void CheckProtectedModifier ()
376 if ((ModFlags
& Modifiers
.PROTECTED
) == 0)
379 if (Parent
.PartialContainer
.Kind
== Kind
.Struct
) {
380 Report
.Error (666, Location
, "`{0}': Structs cannot contain protected members",
381 GetSignatureForError ());
385 if ((Parent
.ModFlags
& Modifiers
.STATIC
) != 0) {
386 Report
.Error (1057, Location
, "`{0}': Static classes cannot contain protected members",
387 GetSignatureForError ());
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 ());
399 public abstract bool Define ();
401 public virtual string DocComment
{
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 ();
422 /// Base Emit method. This is also entry point for CLS-Compliant verification.
424 public virtual void Emit ()
426 if (!RootContext
.VerifyClsCompliance
)
429 if (Report
.WarningLevel
> 0)
430 VerifyClsCompliance ();
433 public bool IsCompilerGenerated
{
435 if ((mod_flags
& Modifiers
.COMPILER_GENERATED
) != 0)
438 return Parent
== null ? false : Parent
.IsCompilerGenerated
;
442 public virtual bool IsUsed
{
443 get { return (caching_flags & Flags.IsUsed) != 0; }
446 protected Report Report
{
448 return Compiler
.Report
;
452 public void SetMemberIsUsed ()
454 caching_flags
|= Flags
.IsUsed
;
458 /// Returns instance of ObsoleteAttribute for this MemberCore
460 public virtual ObsoleteAttribute
GetObsoleteAttribute ()
462 if ((caching_flags
& (Flags
.Obsolete_Undetected
| Flags
.Obsolete
)) == 0)
465 caching_flags
&= ~Flags
.Obsolete_Undetected
;
467 if (OptAttributes
== null)
470 Attribute obsolete_attr
= OptAttributes
.Search (PredefinedAttributes
.Get
.Obsolete
);
471 if (obsolete_attr
== null)
474 caching_flags
|= Flags
.Obsolete
;
476 ObsoleteAttribute obsolete
= obsolete_attr
.GetObsoleteAttribute ();
477 if (obsolete
== null)
484 /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
486 public virtual void CheckObsoleteness (Location loc
)
488 ObsoleteAttribute oa
= GetObsoleteAttribute ();
490 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, Report
);
493 // Access level of a type.
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
;
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
;
519 return AccessLevel
.Public
;
523 // Returns the access level for type `t'
525 static AccessLevel
GetAccessLevelFromType (Type t
)
528 return AccessLevel
.Public
;
529 if (t
.IsNestedPrivate
)
530 return AccessLevel
.Private
;
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
560 if ((mod_flags
& Modifiers
.PRIVATE
) != 0)
563 while (TypeManager
.HasElementType (p
))
564 p
= TypeManager
.GetElementType (p
);
566 if (TypeManager
.IsGenericParameter (p
))
569 if (TypeManager
.IsGenericType (p
)) {
570 foreach (Type t
in TypeManager
.GetTypeArguments (p
)) {
571 if (!IsAccessibleAs (t
))
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
)
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
);
586 case AccessLevel
.Internal
:
587 if (al
== AccessLevel
.Private
|| al
== AccessLevel
.Internal
)
588 same_access_restrictions
= TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
592 case AccessLevel
.Protected
:
593 if (al
== AccessLevel
.Protected
) {
594 same_access_restrictions
= mc
.Parent
.IsBaseType (p_parent
);
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;
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
);
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
);
633 throw new InternalErrorException (al
.ToString ());
637 if (!same_access_restrictions
)
645 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
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
;
658 caching_flags
&= ~Flags
.ClsCompliance_Undetected
;
663 /// Returns true when MemberCore is exposed from assembly.
665 public bool IsExposedFromAssembly ()
667 if ((ModFlags
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
670 DeclSpace parentContainer
= Parent
;
671 while (parentContainer
!= null && parentContainer
.ModFlags
!= 0) {
672 if ((parentContainer
.ModFlags
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
674 parentContainer
= parentContainer
.Parent
;
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
);
695 /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute.
696 /// If no is attribute exists then assembly CLSCompliantAttribute is returned.
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 ();
712 caching_flags
|= Flags
.ClsCompliantAttributeTrue
;
717 // It's null for TypeParameter
721 if (Parent
.GetClsCompliantAttributeValue ()) {
722 caching_flags
|= Flags
.ClsCompliantAttributeTrue
;
729 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
731 protected bool HasClsCompliantAttribute
{
733 if ((caching_flags
& Flags
.HasCompliantAttribute_Undetected
) != 0)
734 GetClsCompliantAttributeValue ();
736 return (caching_flags
& Flags
.HasClsCompliantAttribute
) != 0;
741 /// Returns true when a member supports multiple overloads (methods, indexers, etc)
743 public virtual bool EnableOverloadChecks (MemberCore overload
)
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.
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 ());
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 ());
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 ());
788 if (member_name
.Name
[0] == '_') {
789 Report
.Warning (3008, 1, Location
, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
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
;
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
)
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
{
845 public bool IsObsolete
{
847 if (GetObsoleteAttribute () != null)
850 return Parent
== null ? false : Parent
.IsObsolete
;
854 public bool IsUnsafe
{
856 if ((ModFlags
& Modifiers
.UNSAFE
) != 0)
859 return Parent
== null ? false : Parent
.IsUnsafe
;
863 public bool IsStatic
{
864 get { return (ModFlags & Modifiers.STATIC) != 0; }
871 /// Base class for structs, classes, enumerations and interfaces.
874 /// They all create new declaration spaces. This
875 /// provides the common foundation for managing those name
878 public abstract class DeclSpace
: MemberCore
{
880 /// This points to the actual definition that is being
881 /// created with System.Reflection.Emit
883 public TypeBuilder TypeBuilder
;
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.
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
{
918 else if (Parent
!= null)
919 return Parent
.IsGeneric
;
925 static string[] attribute_targets
= new string [] { "type" }
;
927 public DeclSpace (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
929 : base (parent
, name
, attrs
)
932 Basename
= name
.Basename
;
933 defined_names
= new Hashtable ();
934 PartialContainer
= null;
935 if (name
.TypeArguments
!= null) {
937 count_type_params
= name
.TypeArguments
.Count
;
940 count_type_params
+= parent
.count_type_params
;
944 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
946 protected virtual bool AddToContainer (MemberCore symbol
, string name
)
948 MemberCore mc
= (MemberCore
) defined_names
[name
];
951 defined_names
.Add (name
, symbol
);
955 if (((mc
.ModFlags
| symbol
.ModFlags
) & Modifiers
.COMPILER_GENERATED
) != 0)
958 if (symbol
.EnableOverloadChecks (mc
))
961 InterfaceMemberBase im
= mc
as InterfaceMemberBase
;
962 if (im
!= null && im
.IsExplicitImpl
)
965 Report
.SymbolRelatedToPreviousError (mc
);
966 if ((mc
.ModFlags
& Modifiers
.PARTIAL
) != 0 && (symbol
is ClassOrStruct
|| symbol
is Interface
)) {
967 Error_MissingPartialModifier (symbol
);
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 ());
979 Report
.Error (102, symbol
.Location
,
980 "The type `{0}' already contains a definition for `{1}'",
981 GetSignatureForError (), symbol
.MemberName
.Name
);
987 protected void RemoveFromContainer (string name
)
989 defined_names
.Remove (name
);
993 /// Returns the MemberCore associated with a given name in the declaration
994 /// space. It doesn't return method based symbols !!
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 ()
1020 public virtual void CloseType ()
1022 if ((caching_flags
& Flags
.CloseTypeCreated
) == 0){
1024 TypeBuilder
.CreateType ();
1027 // The try/catch is needed because
1028 // nested enumerations fail to load when they
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; }
1046 /// Should be overriten by the appropriate declaration space
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
);
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)
1089 check_type
= TypeManager
.DropGenericTypeArguments (check_type
);
1090 if (check_type
== tb
)
1093 // TODO: When called from LocalUsingAliasEntry tb is null
1094 // because we are in RootDeclSpace
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
))
1109 TypeAttributes check_attr
= check_type
.Attributes
& TypeAttributes
.VisibilityMask
;
1111 switch (check_attr
){
1112 case TypeAttributes
.Public
:
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
))
1162 type
= type
.BaseType
;
1168 private Type
LookupNestedTypeInHierarchy (string name
)
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
);
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
);
1195 t
= tc
.FindNestedType (name
);
1197 t
= TypeManager
.GetNestedType (ct
, name
);
1200 if ((t
== null) || !CheckAccessLevel (t
))
1203 if (!TypeManager
.IsGenericType (current_type
))
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
);
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
;
1234 TypeParameter tparam
= TypeParameter
.FindTypeParameter (tp
, name
);
1236 e
= new TypeParameterExpr (tparam
, Location
.Null
);
1240 Type t
= LookupNestedTypeInHierarchy (name
);
1243 e
= new TypeExpression (t
, Location
.Null
);
1244 else if (Parent
!= null)
1245 e
= Parent
.LookupNamespaceOrType (name
, loc
, ignore_cs0104
);
1247 e
= NamespaceEntry
.LookupNamespaceOrType (name
, loc
, ignore_cs0104
);
1250 if (errors
== Report
.Errors
)
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.
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 ();
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.
1273 public abstract MemberCache MemberCache
{
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");
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
)
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
];
1310 if (Parent
.CurrentTypeParameters
!= null) {
1311 foreach (TypeParameter tp
in Parent
.CurrentTypeParameters
) {
1312 if (tp
.Name
!= param
.Name
)
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
)
1331 if (constraints_list
!= null) {
1333 80, Location
, "Constraints are not allowed " +
1334 "on non-generic declarations");
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
);
1360 if (constraints_at
.TypeParameter
== name
.Name
) {
1361 constraints
= constraints_at
;
1362 constraints_list
.RemoveAt(ii
);
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
{
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
{
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 ()) {
1431 if (type_params
!= null) {
1432 foreach (TypeParameter tp
in type_params
) {
1433 if (tp
.Constraints
== null)
1436 tp
.Constraints
.VerifyClsCompliance (Report
);
1440 IDictionary cache
= TypeManager
.AllClsTopLevelTypes
;
1444 string lcase
= Name
.ToLower (System
.Globalization
.CultureInfo
.InvariantCulture
);
1445 if (!cache
.Contains (lcase
)) {
1446 cache
.Add (lcase
, this);
1450 object val
= cache
[lcase
];
1452 Type t
= AttributeTester
.GetImportedIgnoreCaseClsType (lcase
);
1455 Report
.SymbolRelatedToPreviousError (t
);
1458 Report
.SymbolRelatedToPreviousError ((DeclSpace
)val
);
1461 Report
.Warning (3005, 1, Location
, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
1467 /// This is a readonly list of MemberInfo's.
1469 public class MemberList
: IList
{
1470 public readonly IList List
;
1474 /// Create a new MemberList from the given IList.
1476 public MemberList (IList list
)
1481 this.List
= new ArrayList ();
1486 /// Concatenate the ILists `first' and `second' to a new MemberList.
1488 public MemberList (IList first
, IList second
)
1490 ArrayList list
= new ArrayList ();
1491 list
.AddRange (first
);
1492 list
.AddRange (second
);
1497 public static readonly MemberList Empty
= new MemberList (new ArrayList (0));
1500 /// Cast the MemberList into a MemberInfo[] array.
1503 /// This is an expensive operation, only use it if it's really necessary.
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
);
1522 public bool IsSynchronized
{
1524 return List
.IsSynchronized
;
1528 public object SyncRoot
{
1530 return List
.SyncRoot
;
1534 public void CopyTo (Array array
, int index
)
1536 List
.CopyTo (array
, index
);
1541 public IEnumerator
GetEnumerator ()
1543 return List
.GetEnumerator ();
1548 public bool IsFixedSize
{
1554 public bool IsReadOnly
{
1560 object IList
.this [int index
] {
1562 return List
[index
];
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
] {
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 ();
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.
1619 public interface IMemberContainer
{
1621 /// The name of the IMemberContainer. This is only used for
1622 /// debugging purposes.
1629 /// The type of this IMemberContainer.
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.
1641 MemberCache BaseCache
{
1646 /// Whether this is an interface.
1653 /// Returns all members of this class with the corresponding MemberTypes
1654 /// and BindingFlags.
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.
1664 MemberList
GetMembers (MemberTypes mt
, BindingFlags bf
);
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.
1681 public class MemberCache
{
1682 public readonly IMemberContainer Container
;
1683 protected Hashtable member_hash
;
1684 protected Hashtable method_hash
;
1687 /// Create a new MemberCache for the given IMemberContainer `container'.
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
);
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 ();
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 ();
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 ();
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
);
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
);
1762 AddCacheContents (cache
);
1768 /// Bootstrap this member cache by doing a deep-copy of our base.
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 ());
1785 // Converts ModFlags to BindingFlags
1787 static BindingFlags
GetBindingFlags (int modifiers
)
1790 if ((modifiers
& Modifiers
.STATIC
) != 0)
1791 bf
= BindingFlags
.Static
;
1793 bf
= BindingFlags
.Instance
;
1795 if ((modifiers
& Modifiers
.PRIVATE
) != 0)
1796 bf
|= BindingFlags
.NonPublic
;
1798 bf
|= BindingFlags
.Public
;
1804 /// Add the contents of `cache' to the member_hash.
1806 void AddCacheContents (MemberCache cache
)
1808 IDictionaryEnumerator it
= cache
.member_hash
.GetEnumerator ();
1809 while (it
.MoveNext ()) {
1810 ArrayList list
= (ArrayList
) member_hash
[it
.Key
];
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
)
1826 /// Add all members from class `container' to the cache.
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
];
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
));
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.
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
);
1912 AddMember (mt
, bf
, container
, gname
, member
);
1918 /// Add all declared and inherited methods from class `type' to the method cache.
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
];
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.
1956 overrides
.Add (curr
);
1957 list
.Add (new CacheEntry (null, base_method
, MemberTypes
.Method
, bf
));
1961 if (overrides
.Count
> 0) {
1962 for (int i
= 0; i
< overrides
.Count
; ++i
)
1963 TypeManager
.RegisterOverride ((MethodBase
) overrides
[i
], curr
);
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
));
1978 /// Compute and return a appropriate `EntryType' magic number for the given
1979 /// MemberTypes and BindingFlags.
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
;
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.
2018 public static bool IsSingleMemberType (MemberTypes 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
:
2035 /// We encode the MemberTypes and BindingFlags of each members in a "magic"
2036 /// number to speed up the searching process.
2039 protected enum EntryType
{
2044 MaskStatic
= Instance
|Static
,
2048 MaskProtection
= Public
|NonPublic
,
2052 Constructor
= 0x020,
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
,
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.
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
))
2099 // Multiple properties: we query those just to find out the indexer
2102 if ((list
.Count
> 0) && (list
[0] is PropertyInfo
))
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.
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
)
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
];
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?
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
) {
2192 if (!do_interface_search
&& DoneSearching (global))
2195 current
= entry
.Container
;
2198 // Is the member of the correct type ?
2199 if ((entry
.EntryType
& type
& EntryType
.MaskType
) == 0)
2202 // Is the member static/non-static ?
2203 if ((entry
.EntryType
& type
& EntryType
.MaskStatic
) == 0)
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
)
2221 if (IsInterfaceBaseInterface (TypeManager
.GetInterfaces (mi
.DeclaringType
), entry
.Member
.DeclaringType
)) {
2222 member_already_exists
= true;
2226 if (member_already_exists
)
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
);
2253 /// Returns true if iterface exists in any base interfaces (ifaces)
2255 static bool IsInterfaceBaseInterface (Type
[] ifaces
, Type ifaceToFind
)
2257 foreach (Type iface
in ifaces
) {
2258 if (iface
== ifaceToFind
)
2261 Type
[] base_ifaces
= TypeManager
.GetInterfaces (iface
);
2262 if (base_ifaces
.Length
> 0 && IsInterfaceBaseInterface (base_ifaces
, ifaceToFind
))
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)
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
;
2284 public MemberInfo
FindBaseEvent (Type invocation_type
, string name
)
2286 ArrayList applicable
= (ArrayList
) member_hash
[name
];
2287 if (applicable
== 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)
2299 EventInfo ei
= (EventInfo
)entry
.Member
;
2300 return ei
.GetAddMethod (true);
2307 // Looks for extension methods with defined name and extension type
2309 public ArrayList
FindExtensionMethods (Assembly thisAssembly
, Type extensionType
, string name
, bool publicOnly
)
2312 if (method_hash
!= null)
2313 entries
= (ArrayList
)method_hash
[name
];
2315 entries
= (ArrayList
)member_hash
[name
];
2317 if (entries
== 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
)
2334 if (!TypeManager
.IsThisOrFriendAssembly (thisAssembly
, mb
.DeclaringType
.Assembly
))
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
;
2348 //if (implicit conversion between ex_type and extensionType exist) {
2349 if (candidates
== null)
2350 candidates
= new ArrayList (2);
2351 candidates
.Add (mb
);
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
];
2373 applicable
= (ArrayList
) member_hash
[name
];
2375 if (applicable
== 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)
2386 PropertyInfo pi
= null;
2387 MethodInfo mi
= null;
2388 FieldInfo fi
= null;
2389 AParametersCollection cmp_attrs
;
2392 if ((entry
.EntryType
& EntryType
.Field
) != 0) {
2393 fi
= (FieldInfo
)entry
.Member
;
2394 cmp_attrs
= ParametersCompiled
.EmptyReadOnlyParameters
;
2396 pi
= (PropertyInfo
) entry
.Member
;
2397 cmp_attrs
= TypeManager
.GetParameterData (pi
);
2400 mi
= (MethodInfo
) entry
.Member
;
2401 cmp_attrs
= TypeManager
.GetParameterData (mi
);
2405 // TODO: Almost duplicate !
2407 switch (fi
.Attributes
& FieldAttributes
.FieldAccessMask
) {
2408 case FieldAttributes
.PrivateScope
:
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
))
2419 case FieldAttributes
.FamANDAssem
:
2420 case FieldAttributes
.Assembly
:
2422 // Check for assembly methods
2424 if (fi
.DeclaringType
.Assembly
!= CodeGen
.Assembly
.Builder
)
2428 return entry
.Member
;
2432 // Check the arguments
2434 if (cmp_attrs
.Count
!= parameters
.Count
)
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
))
2446 if (!TypeManager
.IsEqual (parameters
.Types
[j
], cmp_attrs
.Types
[j
]))
2450 if (j
< cmp_attrs
.Count
)
2454 // check generic arguments for methods
2457 Type
[] cmpGenArgs
= TypeManager
.GetGenericArguments (mi
);
2458 if (generic_method
== null && cmpGenArgs
!= null && cmpGenArgs
.Length
!= 0)
2460 if (generic_method
!= null && cmpGenArgs
!= null && cmpGenArgs
.Length
!= generic_method
.TypeParameters
.Length
)
2465 // get one of the methods because this has the visibility info.
2468 mi
= pi
.GetGetMethod (true);
2470 mi
= pi
.GetSetMethod (true);
2476 switch (mi
.Attributes
& MethodAttributes
.MemberAccessMask
) {
2477 case MethodAttributes
.PrivateScope
:
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
))
2488 case MethodAttributes
.FamANDAssem
:
2489 case MethodAttributes
.Assembly
:
2491 // Check for assembly methods
2493 if (!TypeManager
.IsThisOrFriendAssembly (invocation_type
.Assembly
, mi
.DeclaringType
.Assembly
))
2497 return entry
.Member
;
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.
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)
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)
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)
2543 return entry
.Member
;
2550 Hashtable locase_table
;
2553 /// Builds low-case table for CLS Compliance test
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)
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
:
2574 case EntryType
.Field
:
2575 if ((((FieldInfo
)member_entry
.Member
).Attributes
& (FieldAttributes
.Assembly
| FieldAttributes
.Public
)) == FieldAttributes
.Assembly
)
2579 case EntryType
.Method
:
2580 if ((((MethodInfo
)member_entry
.Member
).Attributes
& (MethodAttributes
.Assembly
| MethodAttributes
.Public
)) == MethodAttributes
.Assembly
)
2584 case EntryType
.Property
:
2585 PropertyInfo pi
= (PropertyInfo
)member_entry
.Member
;
2586 if (pi
.GetSetMethod () == null && pi
.GetGetMethod () == null)
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
)
2597 string lcase
= ((string)entry
.Key
).ToLower (System
.Globalization
.CultureInfo
.InvariantCulture
);
2598 locase_table
[lcase
] = member_entry
.Member
;
2602 return locase_table
;
2605 public Hashtable Members
{
2612 /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
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
];
2624 if (entry
.Member
== this_builder
)
2627 if ((entry
.EntryType
& tested_type
) != tested_type
)
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
)
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 ())
2644 Report
.SymbolRelatedToPreviousError (entry
.Member
);
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 ());
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 ());
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)
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
)
2676 AParametersCollection pd
;
2677 if ((ce
.EntryType
& EntryType
.Property
) != 0) {
2678 pd
= TypeManager
.GetParameterData ((PropertyInfo
) ce
.Member
);
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
)
2688 pd
= TypeManager
.GetParameterData (mb
);
2692 if (p_types
.Length
!= method_param_count
)
2695 if (method_param_count
> 0) {
2696 int ii
= method_param_count
- 1;
2697 Type type_a
, type_b
;
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
))
2712 } while (type_a
== type_b
&& ii
-- != 0);
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
)
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
);
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");
2742 Report
.Error (755, member
.Location
,
2743 "A partial method declaration and partial method implementation must be both an extension method or neither");
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 ());
2751 Report
.Error (663, member
.Location
,
2752 "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
2753 member
.GetSignatureForError ());
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
);
2773 method_b
.SetPartialDefinition (method_a
);
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");
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 ());
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 ());
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",
2815 TypeManager
.GetFullNameSignature (ce
.Member
) :
2816 member
.GetSignatureForError ());
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 ());