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
.Generic
;
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 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);
108 return TypeArguments
== null ? 0 : TypeArguments
.Count
;
112 public bool IsGeneric
{
114 if (TypeArguments
!= null)
116 else if (Left
!= null)
117 return Left
.IsGeneric
;
123 public string GetName (bool is_generic
)
125 string name
= is_generic
? Basename
: Name
;
127 return Left
.GetName (is_generic
) + (is_double_colon
? "::" : ".") + name
;
132 public ATypeNameExpression
GetTypeExpression ()
135 if (TypeArguments
!= null)
136 return new SimpleName (Name
, TypeArguments
, Location
);
138 return new SimpleName (Name
, Location
);
141 if (is_double_colon
) {
142 if (Left
.Left
!= null)
143 throw new InternalErrorException ("The left side of a :: should be an identifier");
144 return new QualifiedAliasMember (Left
.Name
, Name
, TypeArguments
, Location
);
147 Expression lexpr
= Left
.GetTypeExpression ();
148 return new MemberAccess (lexpr
, Name
, TypeArguments
, Location
);
151 public MemberName
Clone ()
153 MemberName left_clone
= Left
== null ? null : Left
.Clone ();
154 return new MemberName (left_clone
, Name
, is_double_colon
, TypeArguments
, Location
);
157 public string Basename
{
159 if (TypeArguments
!= null)
160 return MakeName (Name
, TypeArguments
);
165 public string GetSignatureForError ()
167 string append
= TypeArguments
== null ? "" : "<" + TypeArguments
.GetSignatureForError () + ">";
169 return Name
+ append
;
170 string connect
= is_double_colon
? "::" : ".";
171 return Left
.GetSignatureForError () + connect
+ Name
+ append
;
174 public override bool Equals (object other
)
176 return Equals (other
as MemberName
);
179 public bool Equals (MemberName other
)
183 if (other
== null || Name
!= other
.Name
)
185 if (is_double_colon
!= other
.is_double_colon
)
188 if ((TypeArguments
!= null) &&
189 (other
.TypeArguments
== null || TypeArguments
.Count
!= other
.TypeArguments
.Count
))
192 if ((TypeArguments
== null) && (other
.TypeArguments
!= null))
196 return other
.Left
== null;
198 return Left
.Equals (other
.Left
);
201 public override int GetHashCode ()
203 int hash
= Name
.GetHashCode ();
204 for (MemberName n
= Left
; n
!= null; n
= n
.Left
)
205 hash ^
= n
.Name
.GetHashCode ();
209 if (TypeArguments
!= null)
210 hash ^
= TypeArguments
.Count
<< 5;
212 return hash
& 0x7FFFFFFF;
215 public int CountTypeArguments
{
217 if (TypeArguments
!= null)
218 return TypeArguments
.Count
;
219 else if (Left
!= null)
220 return Left
.CountTypeArguments
;
226 public static string MakeName (string name
, TypeArguments args
)
231 return name
+ "`" + args
.Count
;
234 public static string MakeName (string name
, int count
)
236 return name
+ "`" + count
;
240 public class SimpleMemberName
243 public Location Location
;
245 public SimpleMemberName (string name
, Location loc
)
253 /// Base representation for members. This is used to keep track
254 /// of Name, Location and Modifier flags, and handling Attributes.
256 [System
.Diagnostics
.DebuggerDisplay ("{GetSignatureForError()}")]
257 public abstract class MemberCore
: Attributable
, IMemberContext
, IMemberDefinition
263 protected string cached_name
;
264 // TODO: Remove in favor of MemberName
267 if (cached_name
== null)
268 cached_name
= MemberName
.GetName (!(this is GenericMethod
) && !(this is Method
));
273 string IMemberDefinition
.Name
{
275 return member_name
.Name
;
279 // Is not readonly because of IndexerName attribute
280 private MemberName member_name
;
281 public MemberName MemberName
{
282 get { return member_name; }
286 /// Modifier flags that the user specified in the source code
288 private Modifiers mod_flags
;
289 public Modifiers ModFlags
{
292 if ((value & Modifiers
.COMPILER_GENERATED
) != 0)
293 caching_flags
= Flags
.IsUsed
| Flags
.IsAssigned
;
300 public /*readonly*/ TypeContainer Parent
;
303 /// Location where this declaration happens
305 public Location Location
{
306 get { return member_name.Location; }
310 /// XML documentation comment
312 protected string comment
;
315 /// Represents header string for documentation comment
316 /// for each member types.
318 public abstract string DocCommentHeader { get; }
322 Obsolete_Undetected
= 1, // Obsolete attribute has not been detected yet
323 Obsolete
= 1 << 1, // Type has obsolete attribute
324 ClsCompliance_Undetected
= 1 << 2, // CLS Compliance has not been detected yet
325 ClsCompliant
= 1 << 3, // Type is CLS Compliant
326 CloseTypeCreated
= 1 << 4, // Tracks whether we have Closed the type
327 HasCompliantAttribute_Undetected
= 1 << 5, // Presence of CLSCompliantAttribute has not been detected
328 HasClsCompliantAttribute
= 1 << 6, // Type has CLSCompliantAttribute
329 ClsCompliantAttributeFalse
= 1 << 7, // Member has CLSCompliant(false)
330 Excluded_Undetected
= 1 << 8, // Conditional attribute has not been detected yet
331 Excluded
= 1 << 9, // Method is conditional
332 MethodOverloadsExist
= 1 << 10, // Test for duplication must be performed
334 IsAssigned
= 1 << 12, // Field is assigned
335 HasExplicitLayout
= 1 << 13,
336 PartialDefinitionExists
= 1 << 14, // Set when corresponding partial method definition exists
337 HasStructLayout
= 1 << 15 // Has StructLayoutAttribute
341 /// MemberCore flags at first detected then cached
343 internal Flags caching_flags
;
345 public MemberCore (DeclSpace parent
, MemberName name
, Attributes attrs
)
347 this.Parent
= parent
as TypeContainer
;
349 caching_flags
= Flags
.Obsolete_Undetected
| Flags
.ClsCompliance_Undetected
| Flags
.HasCompliantAttribute_Undetected
| Flags
.Excluded_Undetected
;
350 AddAttributes (attrs
, this);
353 public virtual Assembly Assembly
{
354 get { return Parent.Module.Assembly; }
357 protected virtual void SetMemberName (MemberName new_name
)
359 member_name
= new_name
;
363 protected bool CheckAbstractAndExtern (bool has_block
)
365 if (Parent
.PartialContainer
.Kind
== MemberKind
.Interface
)
369 if ((ModFlags
& Modifiers
.EXTERN
) != 0) {
370 Report
.Error (179, Location
, "`{0}' cannot declare a body because it is marked extern",
371 GetSignatureForError ());
375 if ((ModFlags
& Modifiers
.ABSTRACT
) != 0) {
376 Report
.Error (500, Location
, "`{0}' cannot declare a body because it is marked abstract",
377 GetSignatureForError ());
381 if ((ModFlags
& (Modifiers
.ABSTRACT
| Modifiers
.EXTERN
| Modifiers
.PARTIAL
)) == 0 && !(Parent
is Delegate
)) {
382 if (RootContext
.Version
>= LanguageVersion
.V_3
) {
383 Property
.PropertyMethod pm
= this as Property
.PropertyMethod
;
384 if (pm
is Indexer
.GetIndexerMethod
|| pm
is Indexer
.SetIndexerMethod
)
387 if (pm
!= null && (pm
.Property
.Get
.IsDummy
|| pm
.Property
.Set
.IsDummy
)) {
388 Report
.Error (840, Location
,
389 "`{0}' must have a body because it is not marked abstract or extern. The property can be automatically implemented when you define both accessors",
390 GetSignatureForError ());
395 Report
.Error (501, Location
, "`{0}' must have a body because it is not marked abstract, extern, or partial",
396 GetSignatureForError ());
404 protected void CheckProtectedModifier ()
406 if ((ModFlags
& Modifiers
.PROTECTED
) == 0)
409 if (Parent
.PartialContainer
.Kind
== MemberKind
.Struct
) {
410 Report
.Error (666, Location
, "`{0}': Structs cannot contain protected members",
411 GetSignatureForError ());
415 if ((Parent
.ModFlags
& Modifiers
.STATIC
) != 0) {
416 Report
.Error (1057, Location
, "`{0}': Static classes cannot contain protected members",
417 GetSignatureForError ());
421 if ((Parent
.ModFlags
& Modifiers
.SEALED
) != 0 && (ModFlags
& Modifiers
.OVERRIDE
) == 0 &&
422 !(this is Destructor
)) {
423 Report
.Warning (628, 4, Location
, "`{0}': new protected member declared in sealed class",
424 GetSignatureForError ());
429 public abstract bool Define ();
431 public virtual string DocComment
{
441 // Returns full member name for error message
443 public virtual string GetSignatureForError ()
445 if (Parent
== null || Parent
.Parent
== null)
446 return member_name
.GetSignatureForError ();
448 return Parent
.GetSignatureForError () + "." + member_name
.GetSignatureForError ();
452 /// Base Emit method. This is also entry point for CLS-Compliant verification.
454 public virtual void Emit ()
456 if (!RootContext
.VerifyClsCompliance
)
459 VerifyClsCompliance ();
462 public bool IsCompilerGenerated
{
464 if ((mod_flags
& Modifiers
.COMPILER_GENERATED
) != 0)
467 return Parent
== null ? false : Parent
.IsCompilerGenerated
;
471 public bool IsImported
{
477 public virtual bool IsUsed
{
478 get { return (caching_flags & Flags.IsUsed) != 0; }
481 protected Report Report
{
483 return Compiler
.Report
;
487 public void SetIsUsed ()
489 caching_flags
|= Flags
.IsUsed
;
492 public void SetIsAssigned ()
494 caching_flags
|= Flags
.IsAssigned
;
498 /// Returns instance of ObsoleteAttribute for this MemberCore
500 public virtual ObsoleteAttribute
GetAttributeObsolete ()
502 if ((caching_flags
& (Flags
.Obsolete_Undetected
| Flags
.Obsolete
)) == 0)
505 caching_flags
&= ~Flags
.Obsolete_Undetected
;
507 if (OptAttributes
== null)
510 Attribute obsolete_attr
= OptAttributes
.Search (PredefinedAttributes
.Get
.Obsolete
);
511 if (obsolete_attr
== null)
514 caching_flags
|= Flags
.Obsolete
;
516 ObsoleteAttribute obsolete
= obsolete_attr
.GetObsoleteAttribute ();
517 if (obsolete
== null)
524 /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
526 public virtual void CheckObsoleteness (Location loc
)
528 ObsoleteAttribute oa
= GetAttributeObsolete ();
530 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, Report
);
534 // Checks whether the type P is as accessible as this member
536 public bool IsAccessibleAs (TypeSpec p
)
539 // if M is private, its accessibility is the same as this declspace.
540 // we already know that P is accessible to T before this method, so we
543 if ((mod_flags
& Modifiers
.PRIVATE
) != 0)
546 while (TypeManager
.HasElementType (p
))
547 p
= TypeManager
.GetElementType (p
);
549 if (p
.IsGenericParameter
)
552 for (TypeSpec p_parent
; p
!= null; p
= p_parent
) {
553 p_parent
= p
.DeclaringType
;
556 foreach (TypeSpec t
in p
.TypeArguments
) {
557 if (!IsAccessibleAs (t
))
562 var pAccess
= p
.Modifiers
& Modifiers
.AccessibilityMask
;
563 if (pAccess
== Modifiers
.PUBLIC
)
566 bool same_access_restrictions
= false;
567 for (MemberCore mc
= this; !same_access_restrictions
&& mc
!= null && mc
.Parent
!= null; mc
= mc
.Parent
) {
568 var al
= mc
.ModFlags
& Modifiers
.AccessibilityMask
;
570 case Modifiers
.INTERNAL
:
571 if (al
== Modifiers
.PRIVATE
|| al
== Modifiers
.INTERNAL
)
572 same_access_restrictions
= TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
576 case Modifiers
.PROTECTED
:
577 if (al
== Modifiers
.PROTECTED
) {
578 same_access_restrictions
= mc
.Parent
.IsBaseTypeDefinition (p_parent
);
582 if (al
== Modifiers
.PRIVATE
) {
584 // When type is private and any of its parents derives from
585 // protected type then the type is accessible
587 while (mc
.Parent
!= null) {
588 if (mc
.Parent
.IsBaseTypeDefinition (p_parent
))
589 same_access_restrictions
= true;
596 case Modifiers
.PROTECTED
| Modifiers
.INTERNAL
:
597 if (al
== Modifiers
.INTERNAL
)
598 same_access_restrictions
= TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
599 else if (al
== Modifiers
.PROTECTED
)
600 same_access_restrictions
= mc
.Parent
.IsBaseTypeDefinition (p_parent
);
601 else if (al
== (Modifiers
.PROTECTED
| Modifiers
.INTERNAL
))
602 same_access_restrictions
= mc
.Parent
.IsBaseTypeDefinition (p_parent
) &&
603 TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
606 case Modifiers
.PRIVATE
:
608 // Both are private and share same parent
610 if (al
== Modifiers
.PRIVATE
) {
611 var decl
= mc
.Parent
;
613 same_access_restrictions
= decl
.CurrentType
== p_parent
;
614 } while (!same_access_restrictions
&& !decl
.IsTopLevel
&& (decl
= decl
.Parent
) != null);
620 throw new InternalErrorException (al
.ToString ());
624 if (!same_access_restrictions
)
632 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
634 public override bool IsClsComplianceRequired ()
636 if ((caching_flags
& Flags
.ClsCompliance_Undetected
) == 0)
637 return (caching_flags
& Flags
.ClsCompliant
) != 0;
639 caching_flags
&= ~Flags
.ClsCompliance_Undetected
;
641 if (HasClsCompliantAttribute
) {
642 if ((caching_flags
& Flags
.ClsCompliantAttributeFalse
) != 0)
645 caching_flags
|= Flags
.ClsCompliant
;
649 if (Parent
.PartialContainer
.IsClsComplianceRequired ()) {
650 caching_flags
|= Flags
.ClsCompliant
;
657 public virtual string[] ConditionalConditions ()
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
.PartialContainer
;
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 (TypeSpec extensionType
, string name
, int arity
, Location loc
)
681 return Parent
.LookupExtensionMethod (extensionType
, name
, arity
, loc
);
684 public virtual FullNamedExpression
LookupNamespaceAlias (string name
)
686 return Parent
.NamespaceEntry
.LookupNamespaceAlias (name
);
689 public virtual FullNamedExpression
LookupNamespaceOrType (string name
, int arity
, Location loc
, bool ignore_cs0104
)
691 return Parent
.LookupNamespaceOrType (name
, arity
, 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 bool IsNotCLSCompliant ()
700 if ((caching_flags
& Flags
.HasCompliantAttribute_Undetected
) == 0)
701 return (caching_flags
& Flags
.ClsCompliantAttributeFalse
) != 0;
703 caching_flags
&= ~Flags
.HasCompliantAttribute_Undetected
;
705 if (OptAttributes
!= null) {
706 Attribute cls_attribute
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
707 if (cls_attribute
!= null) {
708 caching_flags
|= Flags
.HasClsCompliantAttribute
;
709 if (cls_attribute
.GetClsCompliantAttributeValue ())
712 caching_flags
|= Flags
.ClsCompliantAttributeFalse
;
721 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
723 protected bool HasClsCompliantAttribute
{
725 if ((caching_flags
& Flags
.HasCompliantAttribute_Undetected
) != 0)
726 IsNotCLSCompliant ();
728 return (caching_flags
& Flags
.HasClsCompliantAttribute
) != 0;
733 /// Returns true when a member supports multiple overloads (methods, indexers, etc)
735 public virtual bool EnableOverloadChecks (MemberCore overload
)
741 /// The main virtual method for CLS-Compliant verifications.
742 /// The method returns true if member is CLS-Compliant and false if member is not
743 /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
744 /// and add their extra verifications.
746 protected virtual bool VerifyClsCompliance ()
748 if (HasClsCompliantAttribute
) {
749 if (CodeGen
.Assembly
.ClsCompliantAttribute
== null) {
750 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
751 if ((caching_flags
& Flags
.ClsCompliantAttributeFalse
) != 0) {
752 Report
.Warning (3021, 2, a
.Location
,
753 "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant",
754 GetSignatureForError ());
756 Report
.Warning (3014, 1, a
.Location
,
757 "`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant",
758 GetSignatureForError ());
763 if (!IsExposedFromAssembly ()) {
764 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
765 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 ());
769 if ((caching_flags
& Flags
.ClsCompliantAttributeFalse
) != 0) {
770 if (Parent
.Kind
== MemberKind
.Interface
&& Parent
.IsClsComplianceRequired ()) {
771 Report
.Warning (3010, 1, Location
, "`{0}': CLS-compliant interfaces must have only CLS-compliant members", GetSignatureForError ());
772 } else if (Parent
.Kind
== MemberKind
.Class
&& (ModFlags
& Modifiers
.ABSTRACT
) != 0 && Parent
.IsClsComplianceRequired ()) {
773 Report
.Warning (3011, 1, Location
, "`{0}': only CLS-compliant members can be abstract", GetSignatureForError ());
779 if (Parent
.Parent
!= null && !Parent
.IsClsComplianceRequired ()) {
780 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
781 Report
.Warning (3018, 1, a
.Location
, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
782 GetSignatureForError (), Parent
.GetSignatureForError ());
786 if (!IsExposedFromAssembly ())
789 if (!Parent
.PartialContainer
.IsClsComplianceRequired ())
793 if (member_name
.Name
[0] == '_') {
794 Report
.Warning (3008, 1, Location
, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
801 // Raised (and passed an XmlElement that contains the comment)
802 // when GenerateDocComment is writing documentation expectedly.
804 internal virtual void OnGenerateDocComment (XmlElement intermediateNode
)
809 // Returns a string that represents the signature for this
810 // member which should be used in XML documentation.
812 public virtual string GetDocCommentName (DeclSpace ds
)
814 if (ds
== null || this is DeclSpace
)
815 return DocCommentHeader
+ Name
;
817 return String
.Concat (DocCommentHeader
, ds
.Name
, ".", Name
);
821 // Generates xml doc comments (if any), and if required,
822 // handle warning report.
824 internal virtual void GenerateDocComment (DeclSpace ds
)
827 DocUtil
.GenerateDocComment (this, ds
, Report
);
828 } catch (Exception e
) {
829 throw new InternalErrorException (this, e
);
833 #region IMemberContext Members
835 public virtual CompilerContext Compiler
{
836 get { return Parent.Compiler; }
839 public virtual TypeSpec CurrentType
{
840 get { return Parent.CurrentType; }
843 public MemberCore CurrentMemberDefinition
{
847 public virtual TypeParameter
[] CurrentTypeParameters
{
851 public virtual bool HasUnresolvedConstraints
{
852 get { return false; }
855 public bool IsObsolete
{
857 if (GetAttributeObsolete () != null)
860 return Parent
== null ? false : Parent
.IsObsolete
;
864 public bool IsUnsafe
{
866 if ((ModFlags
& Modifiers
.UNSAFE
) != 0)
869 return Parent
== null ? false : Parent
.IsUnsafe
;
873 public bool IsStatic
{
875 return (ModFlags
& Modifiers
.STATIC
) != 0;
883 // Base member specification. A member specification contains
884 // member details which can alter in the context (e.g. generic instances)
886 public abstract class MemberSpec
889 protected enum StateFlags
891 Obsolete_Undetected
= 1, // Obsolete attribute has not been detected yet
892 Obsolete
= 1 << 1, // Member has obsolete attribute
893 CLSCompliant_Undetected
= 1 << 3, // CLSCompliant attribute has not been detected yet
894 CLSCompliant
= 1 << 4, // Member is CLS Compliant
896 IsAccessor
= 1 << 9, // Method is an accessor
897 IsGeneric
= 1 << 10, // Member contains type arguments
899 PendingMetaInflate
= 1 << 12,
900 PendingMakeMethod
= 1 << 13,
901 PendingMemberCacheMembers
= 1 << 14,
902 PendingBaseTypeInflate
= 1 << 15,
903 InterfacesExpanded
= 1 << 16,
904 IsNotRealProperty
= 1 << 17,
907 protected Modifiers modifiers
;
908 protected StateFlags state
;
909 protected IMemberDefinition definition
;
910 public readonly MemberKind Kind
;
911 protected TypeSpec declaringType
;
915 public int ID
= counter
++;
918 protected MemberSpec (MemberKind kind
, TypeSpec declaringType
, IMemberDefinition definition
, Modifiers modifiers
)
921 this.declaringType
= declaringType
;
922 this.definition
= definition
;
923 this.modifiers
= modifiers
;
925 state
= StateFlags
.Obsolete_Undetected
| StateFlags
.CLSCompliant_Undetected
;
930 public Assembly Assembly
{
932 return definition
.Assembly
;
936 public virtual int Arity
{
942 public TypeSpec DeclaringType
{
944 return declaringType
;
947 declaringType
= value;
951 public IMemberDefinition MemberDefinition
{
957 public Modifiers Modifiers
{
966 public virtual string Name
{
968 return definition
.Name
;
972 public bool IsAbstract
{
973 get { return (modifiers & Modifiers.ABSTRACT) != 0; }
976 public bool IsAccessor
{
978 return (state
& StateFlags
.IsAccessor
) != 0;
981 state
= value ? state
| StateFlags
.IsAccessor
: state
& ~StateFlags
.IsAccessor
;
986 // Return true when this member is a generic in C# terms
987 // A nested non-generic type of generic type will return false
989 public bool IsGeneric
{
991 return (state
& StateFlags
.IsGeneric
) != 0;
994 state
= value ? state
| StateFlags
.IsGeneric
: state
& ~StateFlags
.IsGeneric
;
998 public bool IsPrivate
{
999 get { return (modifiers & Modifiers.PRIVATE) != 0; }
1002 public bool IsStatic
{
1004 return (modifiers
& Modifiers
.STATIC
) != 0;
1010 public virtual ObsoleteAttribute
GetAttributeObsolete ()
1012 if ((state
& (StateFlags
.Obsolete
| StateFlags
.Obsolete_Undetected
)) == 0)
1015 state
&= ~StateFlags
.Obsolete_Undetected
;
1017 var oa
= definition
.GetAttributeObsolete ();
1019 state
|= StateFlags
.Obsolete
;
1024 protected virtual bool IsNotCLSCompliant ()
1026 return MemberDefinition
.IsNotCLSCompliant ();
1029 public virtual string GetSignatureForError ()
1031 var bf
= MemberDefinition
as Property
.BackingField
;
1032 var name
= bf
== null ? Name
: bf
.OriginalName
;
1033 return DeclaringType
.GetSignatureForError () + "." + name
;
1036 public virtual MemberSpec
InflateMember (TypeParameterInflator inflator
)
1038 var inflated
= (MemberSpec
) MemberwiseClone ();
1039 inflated
.declaringType
= inflator
.TypeInstance
;
1040 inflated
.state
|= StateFlags
.PendingMetaInflate
;
1042 if (inflated
.ID
> 0)
1043 inflated
.ID
= -inflated
.ID
;
1049 // Returns member CLS compliance based on full member hierarchy
1051 public bool IsCLSCompliant ()
1053 if ((state
& StateFlags
.CLSCompliant_Undetected
) != 0) {
1054 state
&= ~StateFlags
.CLSCompliant_Undetected
;
1056 if (IsNotCLSCompliant ())
1060 if (DeclaringType
!= null) {
1061 compliant
= DeclaringType
.IsCLSCompliant ();
1063 // TODO: NEED AssemblySpec
1064 if (MemberDefinition
.IsImported
) {
1065 var attr
= MemberDefinition
.Assembly
.GetCustomAttributes (typeof (CLSCompliantAttribute
), false);
1066 compliant
= attr
.Length
> 0 && ((CLSCompliantAttribute
) attr
[0]).IsCompliant
;
1068 compliant
= CodeGen
.Assembly
.IsClsCompliant
;
1073 state
|= StateFlags
.CLSCompliant
;
1076 return (state
& StateFlags
.CLSCompliant
) != 0;
1079 public bool IsConditionallyExcluded (Location loc
)
1081 if ((Kind
& (MemberKind
.Class
| MemberKind
.Method
)) == 0)
1084 var conditions
= MemberDefinition
.ConditionalConditions ();
1085 if (conditions
== null)
1088 foreach (var condition
in conditions
) {
1089 if (loc
.CompilationUnit
.IsConditionalDefined (condition
))
1096 public override string ToString ()
1098 return GetSignatureForError ();
1103 // Member details which are same between all member
1106 public interface IMemberDefinition
1108 Assembly Assembly { get; }
1109 string Name { get; }
1110 bool IsImported { get; }
1112 string[] ConditionalConditions ();
1113 ObsoleteAttribute
GetAttributeObsolete ();
1114 bool IsNotCLSCompliant ();
1115 void SetIsAssigned ();
1119 public interface IParametersMember
: IInterfaceMemberSpec
1121 AParametersCollection Parameters { get; }
1124 public interface IInterfaceMemberSpec
1126 TypeSpec MemberType { get; }
1130 // Base type container declaration. It exists to handle partial types
1131 // which share same definition (PartialContainer) but have different
1134 public abstract class DeclSpace
: MemberCore
{
1136 /// This points to the actual definition that is being
1137 /// created with System.Reflection.Emit
1139 public TypeBuilder TypeBuilder
;
1142 // This is the namespace in which this typecontainer
1143 // was declared. We use this to resolve names.
1145 public NamespaceEntry NamespaceEntry
;
1147 private Dictionary
<string, FullNamedExpression
> Cache
= new Dictionary
<string, FullNamedExpression
> ();
1149 public readonly string Basename
;
1151 protected Dictionary
<string, MemberCore
> defined_names
;
1153 public TypeContainer PartialContainer
;
1155 protected readonly bool is_generic
;
1156 readonly int count_type_params
;
1157 protected TypeParameter
[] type_params
;
1158 TypeParameter
[] type_param_list
;
1161 // Whether we are Generic
1163 public bool IsGeneric
{
1167 else if (Parent
!= null)
1168 return Parent
.IsGeneric
;
1174 static string[] attribute_targets
= new string [] { "type" }
;
1176 public DeclSpace (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
1178 : base (parent
, name
, attrs
)
1180 NamespaceEntry
= ns
;
1181 Basename
= name
.Basename
;
1182 defined_names
= new Dictionary
<string, MemberCore
> ();
1183 PartialContainer
= null;
1184 if (name
.TypeArguments
!= null) {
1186 count_type_params
= name
.TypeArguments
.Count
;
1189 count_type_params
+= parent
.count_type_params
;
1193 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
1195 protected virtual bool AddToContainer (MemberCore symbol
, string name
)
1198 if (!defined_names
.TryGetValue (name
, out mc
)) {
1199 defined_names
.Add (name
, symbol
);
1203 if (((mc
.ModFlags
| symbol
.ModFlags
) & Modifiers
.COMPILER_GENERATED
) != 0)
1206 if (symbol
.EnableOverloadChecks (mc
))
1209 InterfaceMemberBase im
= mc
as InterfaceMemberBase
;
1210 if (im
!= null && im
.IsExplicitImpl
)
1213 Report
.SymbolRelatedToPreviousError (mc
);
1214 if ((mc
.ModFlags
& Modifiers
.PARTIAL
) != 0 && (symbol
is ClassOrStruct
|| symbol
is Interface
)) {
1215 Error_MissingPartialModifier (symbol
);
1219 if (this is ModuleContainer
) {
1220 Report
.Error (101, symbol
.Location
,
1221 "The namespace `{0}' already contains a definition for `{1}'",
1222 ((DeclSpace
)symbol
).NamespaceEntry
.GetSignatureForError (), symbol
.MemberName
.Name
);
1223 } else if (symbol
is TypeParameter
) {
1224 Report
.Error (692, symbol
.Location
,
1225 "Duplicate type parameter `{0}'", symbol
.GetSignatureForError ());
1227 Report
.Error (102, symbol
.Location
,
1228 "The type `{0}' already contains a definition for `{1}'",
1229 GetSignatureForError (), symbol
.MemberName
.Name
);
1235 protected void RemoveFromContainer (string name
)
1237 defined_names
.Remove (name
);
1241 /// Returns the MemberCore associated with a given name in the declaration
1242 /// space. It doesn't return method based symbols !!
1245 public MemberCore
GetDefinition (string name
)
1247 MemberCore mc
= null;
1248 defined_names
.TryGetValue (name
, out mc
);
1253 // root_types contains all the types. All TopLevel types
1254 // hence have a parent that points to `root_types', that is
1255 // why there is a non-obvious test down here.
1257 public bool IsTopLevel
{
1258 get { return (Parent != null && Parent.Parent == null); }
1261 public virtual bool IsUnmanagedType ()
1266 protected virtual TypeAttributes TypeAttr
{
1267 get { return Module.DefaultCharSetType; }
1271 /// Should be overriten by the appropriate declaration space
1273 public abstract TypeBuilder
DefineType ();
1275 protected void Error_MissingPartialModifier (MemberCore type
)
1277 Report
.Error (260, type
.Location
,
1278 "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists",
1279 type
.GetSignatureForError ());
1282 public override string GetSignatureForError ()
1284 return MemberName
.GetSignatureForError ();
1287 public bool CheckAccessLevel (TypeSpec check_type
)
1289 TypeSpec tb
= PartialContainer
.Definition
;
1290 check_type
= check_type
.GetDefinition ();
1292 var check_attr
= check_type
.Modifiers
& Modifiers
.AccessibilityMask
;
1294 switch (check_attr
){
1295 case Modifiers
.PUBLIC
:
1298 case Modifiers
.INTERNAL
:
1299 return TypeManager
.IsThisOrFriendAssembly (Assembly
, check_type
.Assembly
);
1301 case Modifiers
.PRIVATE
:
1302 TypeSpec declaring
= check_type
.DeclaringType
;
1303 return tb
== declaring
.GetDefinition () || TypeManager
.IsNestedChildOf (tb
, declaring
);
1305 case Modifiers
.PROTECTED
:
1307 // Only accessible to methods in current type or any subtypes
1309 return TypeManager
.IsNestedFamilyAccessible (tb
, check_type
.DeclaringType
);
1311 case Modifiers
.PROTECTED
| Modifiers
.INTERNAL
:
1312 if (TypeManager
.IsThisOrFriendAssembly (Assembly
, check_type
.Assembly
))
1315 goto case Modifiers
.PROTECTED
;
1318 throw new NotImplementedException (check_attr
.ToString ());
1321 private TypeSpec
LookupNestedTypeInHierarchy (string name
, int arity
)
1323 // TODO: GenericMethod only
1324 if (PartialContainer
== null)
1327 // Has any nested type
1328 // Does not work, because base type can have
1329 //if (PartialContainer.Types == null)
1332 var container
= PartialContainer
.CurrentType
;
1334 // Is not Root container
1335 if (container
== null)
1338 var t
= MemberCache
.FindNestedType (container
, name
, arity
);
1342 // FIXME: Breaks error reporting
1343 if (!CheckAccessLevel (t
))
1350 // Public function used to locate types.
1352 // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
1354 // Returns: Type or null if they type can not be found.
1356 public override FullNamedExpression
LookupNamespaceOrType (string name
, int arity
, Location loc
, bool ignore_cs0104
)
1358 FullNamedExpression e
;
1359 if (arity
== 0 && Cache
.TryGetValue (name
, out e
))
1363 int errors
= Report
.Errors
;
1366 TypeParameter
[] tp
= CurrentTypeParameters
;
1368 TypeParameter tparam
= TypeParameter
.FindTypeParameter (tp
, name
);
1370 e
= new TypeParameterExpr (tparam
, Location
.Null
);
1375 TypeSpec t
= LookupNestedTypeInHierarchy (name
, arity
);
1378 e
= new TypeExpression (t
, Location
.Null
);
1379 else if (Parent
!= null)
1380 e
= Parent
.LookupNamespaceOrType (name
, arity
, loc
, ignore_cs0104
);
1382 e
= NamespaceEntry
.LookupNamespaceOrType (name
, arity
, loc
, ignore_cs0104
);
1385 // TODO MemberCache: How to cache arity stuff ?
1386 if (errors
== Report
.Errors
&& arity
== 0)
1392 public override Assembly Assembly
{
1393 get { return Module.Assembly; }
1396 public virtual ModuleContainer Module
{
1397 get { return Parent.Module; }
1400 TypeParameter
[] initialize_type_params ()
1402 if (type_param_list
!= null)
1403 return type_param_list
;
1405 DeclSpace the_parent
= Parent
;
1406 if (this is GenericMethod
)
1409 var list
= new List
<TypeParameter
> ();
1410 if (the_parent
!= null && the_parent
.IsGeneric
) {
1411 // FIXME: move generics info out of DeclSpace
1412 TypeParameter
[] parent_params
= the_parent
.TypeParameters
;
1413 list
.AddRange (parent_params
);
1416 int count
= type_params
!= null ? type_params
.Length
: 0;
1417 for (int i
= 0; i
< count
; i
++) {
1418 TypeParameter param
= type_params
[i
];
1420 if (Parent
.CurrentTypeParameters
!= null) {
1421 foreach (TypeParameter tp
in Parent
.CurrentTypeParameters
) {
1422 if (tp
.Name
!= param
.Name
)
1425 Report
.SymbolRelatedToPreviousError (tp
.Location
, null);
1426 Report
.Warning (693, 3, param
.Location
,
1427 "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
1428 param
.Name
, Parent
.GetSignatureForError ());
1433 type_param_list
= new TypeParameter
[list
.Count
];
1434 list
.CopyTo (type_param_list
, 0);
1435 return type_param_list
;
1438 public virtual void SetParameterInfo (List
<Constraints
> constraints_list
)
1441 if (constraints_list
!= null) {
1443 80, Location
, "Constraints are not allowed " +
1444 "on non-generic declarations");
1450 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1451 type_params
= new TypeParameter
[names
.Length
];
1454 // Register all the names
1456 for (int i
= 0; i
< type_params
.Length
; i
++) {
1457 TypeParameterName name
= names
[i
];
1459 Constraints constraints
= null;
1460 if (constraints_list
!= null) {
1461 int total
= constraints_list
.Count
;
1462 for (int ii
= 0; ii
< total
; ++ii
) {
1463 Constraints constraints_at
= (Constraints
)constraints_list
[ii
];
1464 // TODO: it is used by iterators only
1465 if (constraints_at
== null) {
1466 constraints_list
.RemoveAt (ii
);
1470 if (constraints_at
.TypeParameter
.Value
== name
.Name
) {
1471 constraints
= constraints_at
;
1472 constraints_list
.RemoveAt(ii
);
1478 Variance variance
= name
.Variance
;
1479 if (name
.Variance
!= Variance
.None
&& !(this is Delegate
|| this is Interface
)) {
1480 Report
.Error (1960, name
.Location
, "Variant type parameters can only be used with interfaces and delegates");
1481 variance
= Variance
.None
;
1484 type_params
[i
] = new TypeParameter (
1485 Parent
, i
, new MemberName (name
.Name
, Location
), constraints
, name
.OptAttributes
, variance
);
1487 AddToContainer (type_params
[i
], name
.Name
);
1490 if (constraints_list
!= null && constraints_list
.Count
> 0) {
1491 foreach (Constraints constraint
in constraints_list
) {
1492 Report
.Error(699, constraint
.Location
, "`{0}': A constraint references nonexistent type parameter `{1}'",
1493 GetSignatureForError (), constraint
.TypeParameter
.Value
);
1498 protected TypeParameter
[] TypeParameters
{
1501 throw new InvalidOperationException ();
1502 if ((PartialContainer
!= null) && (PartialContainer
!= this))
1503 return PartialContainer
.TypeParameters
;
1504 if (type_param_list
== null)
1505 initialize_type_params ();
1507 return type_param_list
;
1511 public int CountTypeParameters
{
1513 return count_type_params
;
1517 public override string[] ValidAttributeTargets
{
1518 get { return attribute_targets; }
1521 protected override bool VerifyClsCompliance ()
1523 if (!base.VerifyClsCompliance ()) {
1527 if (type_params
!= null) {
1528 foreach (TypeParameter tp
in type_params
) {
1529 tp
.VerifyClsCompliance ();