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 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
;
234 public class SimpleMemberName
237 public Location Location
;
239 public SimpleMemberName (string name
, Location loc
)
247 /// Base representation for members. This is used to keep track
248 /// of Name, Location and Modifier flags, and handling Attributes.
250 public abstract class MemberCore
: Attributable
, IMemberContext
, IMemberDefinition
256 protected string cached_name
;
257 // TODO: Remove in favor of MemberName
260 if (cached_name
== null)
261 cached_name
= MemberName
.GetName (!(this is GenericMethod
) && !(this is Method
));
266 // Is not readonly because of IndexerName attribute
267 private MemberName member_name
;
268 public MemberName MemberName
{
269 get { return member_name; }
273 /// Modifier flags that the user specified in the source code
275 private Modifiers mod_flags
;
276 public Modifiers ModFlags
{
279 if ((value & Modifiers
.COMPILER_GENERATED
) != 0)
280 caching_flags
= Flags
.IsUsed
| Flags
.IsAssigned
;
287 public /*readonly*/ DeclSpace Parent
;
290 /// Location where this declaration happens
292 public Location Location
{
293 get { return member_name.Location; }
297 /// XML documentation comment
299 protected string comment
;
302 /// Represents header string for documentation comment
303 /// for each member types.
305 public abstract string DocCommentHeader { get; }
309 Obsolete_Undetected
= 1, // Obsolete attribute has not been detected yet
310 Obsolete
= 1 << 1, // Type has obsolete attribute
311 ClsCompliance_Undetected
= 1 << 2, // CLS Compliance has not been detected yet
312 ClsCompliant
= 1 << 3, // Type is CLS Compliant
313 CloseTypeCreated
= 1 << 4, // Tracks whether we have Closed the type
314 HasCompliantAttribute_Undetected
= 1 << 5, // Presence of CLSCompliantAttribute has not been detected
315 HasClsCompliantAttribute
= 1 << 6, // Type has CLSCompliantAttribute
316 ClsCompliantAttributeTrue
= 1 << 7, // Type has CLSCompliant (true)
317 Excluded_Undetected
= 1 << 8, // Conditional attribute has not been detected yet
318 Excluded
= 1 << 9, // Method is conditional
319 MethodOverloadsExist
= 1 << 10, // Test for duplication must be performed
321 IsAssigned
= 1 << 12, // Field is assigned
322 HasExplicitLayout
= 1 << 13,
323 PartialDefinitionExists
= 1 << 14, // Set when corresponding partial method definition exists
324 HasStructLayout
= 1 << 15 // Has StructLayoutAttribute
328 /// MemberCore flags at first detected then cached
330 internal Flags caching_flags
;
332 public MemberCore (DeclSpace parent
, MemberName name
, Attributes attrs
)
334 this.Parent
= parent
;
336 caching_flags
= Flags
.Obsolete_Undetected
| Flags
.ClsCompliance_Undetected
| Flags
.HasCompliantAttribute_Undetected
| Flags
.Excluded_Undetected
;
337 AddAttributes (attrs
, this);
340 protected virtual void SetMemberName (MemberName new_name
)
342 member_name
= new_name
;
346 protected bool CheckAbstractAndExtern (bool has_block
)
348 if (Parent
.PartialContainer
.Kind
== MemberKind
.Interface
)
352 if ((ModFlags
& Modifiers
.EXTERN
) != 0) {
353 Report
.Error (179, Location
, "`{0}' cannot declare a body because it is marked extern",
354 GetSignatureForError ());
358 if ((ModFlags
& Modifiers
.ABSTRACT
) != 0) {
359 Report
.Error (500, Location
, "`{0}' cannot declare a body because it is marked abstract",
360 GetSignatureForError ());
364 if ((ModFlags
& (Modifiers
.ABSTRACT
| Modifiers
.EXTERN
| Modifiers
.PARTIAL
)) == 0 && !(Parent
is Delegate
)) {
365 if (RootContext
.Version
>= LanguageVersion
.V_3
) {
366 Property
.PropertyMethod pm
= this as Property
.PropertyMethod
;
367 if (pm
is Indexer
.GetIndexerMethod
|| pm
is Indexer
.SetIndexerMethod
)
370 if (pm
!= null && (pm
.Property
.Get
.IsDummy
|| pm
.Property
.Set
.IsDummy
)) {
371 Report
.Error (840, Location
,
372 "`{0}' must have a body because it is not marked abstract or extern. The property can be automatically implemented when you define both accessors",
373 GetSignatureForError ());
378 Report
.Error (501, Location
, "`{0}' must have a body because it is not marked abstract, extern, or partial",
379 GetSignatureForError ());
387 protected void CheckProtectedModifier ()
389 if ((ModFlags
& Modifiers
.PROTECTED
) == 0)
392 if (Parent
.PartialContainer
.Kind
== MemberKind
.Struct
) {
393 Report
.Error (666, Location
, "`{0}': Structs cannot contain protected members",
394 GetSignatureForError ());
398 if ((Parent
.ModFlags
& Modifiers
.STATIC
) != 0) {
399 Report
.Error (1057, Location
, "`{0}': Static classes cannot contain protected members",
400 GetSignatureForError ());
404 if ((Parent
.ModFlags
& Modifiers
.SEALED
) != 0 && (ModFlags
& Modifiers
.OVERRIDE
) == 0 &&
405 !(this is Destructor
)) {
406 Report
.Warning (628, 4, Location
, "`{0}': new protected member declared in sealed class",
407 GetSignatureForError ());
412 public abstract bool Define ();
414 public virtual string DocComment
{
424 // Returns full member name for error message
426 public virtual string GetSignatureForError ()
428 if (Parent
== null || Parent
.Parent
== null)
429 return member_name
.GetSignatureForError ();
431 return Parent
.GetSignatureForError () + "." + member_name
.GetSignatureForError ();
435 /// Base Emit method. This is also entry point for CLS-Compliant verification.
437 public virtual void Emit ()
439 if (!RootContext
.VerifyClsCompliance
)
442 if (Report
.WarningLevel
> 0)
443 VerifyClsCompliance ();
446 public bool IsCompilerGenerated
{
448 if ((mod_flags
& Modifiers
.COMPILER_GENERATED
) != 0)
451 return Parent
== null ? false : Parent
.IsCompilerGenerated
;
455 public virtual bool IsUsed
{
456 get { return (caching_flags & Flags.IsUsed) != 0; }
459 protected Report Report
{
461 return Compiler
.Report
;
465 public void SetIsUsed ()
467 caching_flags
|= Flags
.IsUsed
;
471 /// Returns instance of ObsoleteAttribute for this MemberCore
473 public virtual ObsoleteAttribute
GetObsoleteAttribute ()
475 if ((caching_flags
& (Flags
.Obsolete_Undetected
| Flags
.Obsolete
)) == 0)
478 caching_flags
&= ~Flags
.Obsolete_Undetected
;
480 if (OptAttributes
== null)
483 Attribute obsolete_attr
= OptAttributes
.Search (PredefinedAttributes
.Get
.Obsolete
);
484 if (obsolete_attr
== null)
487 caching_flags
|= Flags
.Obsolete
;
489 ObsoleteAttribute obsolete
= obsolete_attr
.GetObsoleteAttribute ();
490 if (obsolete
== null)
497 /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
499 public virtual void CheckObsoleteness (Location loc
)
501 ObsoleteAttribute oa
= GetObsoleteAttribute ();
503 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, Report
);
507 // Returns the access level for type `t'
509 static Modifiers
GetAccessLevelFromType (Type type
)
511 var ma
= type
.Attributes
;
513 switch (ma
& TypeAttributes
.VisibilityMask
) {
514 case TypeAttributes
.Public
:
515 case TypeAttributes
.NestedPublic
:
516 mod
= Modifiers
.PUBLIC
;
518 case TypeAttributes
.NestedPrivate
:
519 mod
= Modifiers
.PRIVATE
;
521 case TypeAttributes
.NestedFamily
:
522 mod
= Modifiers
.PROTECTED
;
524 case TypeAttributes
.NestedFamORAssem
:
525 mod
= Modifiers
.PROTECTED
| Modifiers
.INTERNAL
;
528 mod
= Modifiers
.INTERNAL
;
536 // Checks whether the type P is as accessible as this member
538 public bool IsAccessibleAs (Type p
)
541 // if M is private, its accessibility is the same as this declspace.
542 // we already know that P is accessible to T before this method, so we
545 if ((mod_flags
& Modifiers
.PRIVATE
) != 0)
548 while (TypeManager
.HasElementType (p
))
549 p
= TypeManager
.GetElementType (p
);
551 if (TypeManager
.IsGenericParameter (p
))
554 if (TypeManager
.IsGenericType (p
)) {
555 foreach (Type t
in TypeManager
.GetTypeArguments (p
)) {
556 if (!IsAccessibleAs (t
))
561 for (Type p_parent
= null; p
!= null; p
= p_parent
) {
562 p_parent
= p
.DeclaringType
;
563 var pAccess
= GetAccessLevelFromType (p
);
564 if (pAccess
== Modifiers
.PUBLIC
)
567 bool same_access_restrictions
= false;
568 for (MemberCore mc
= this; !same_access_restrictions
&& mc
!= null && mc
.Parent
!= null; mc
= mc
.Parent
) {
569 var al
= mc
.ModFlags
& Modifiers
.AccessibilityMask
;
571 case Modifiers
.INTERNAL
:
572 if (al
== Modifiers
.PRIVATE
|| al
== Modifiers
.INTERNAL
)
573 same_access_restrictions
= TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
577 case Modifiers
.PROTECTED
:
578 if (al
== Modifiers
.PROTECTED
) {
579 same_access_restrictions
= mc
.Parent
.IsBaseType (p_parent
);
583 if (al
== Modifiers
.PRIVATE
) {
585 // When type is private and any of its parents derives from
586 // protected type then the type is accessible
588 while (mc
.Parent
!= null) {
589 if (mc
.Parent
.IsBaseType (p_parent
))
590 same_access_restrictions
= true;
597 case Modifiers
.PROTECTED
| Modifiers
.INTERNAL
:
598 if (al
== Modifiers
.INTERNAL
)
599 same_access_restrictions
= TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
600 else if (al
== Modifiers
.PROTECTED
)
601 same_access_restrictions
= mc
.Parent
.IsBaseType (p_parent
);
602 else if (al
== (Modifiers
.PROTECTED
| Modifiers
.INTERNAL
))
603 same_access_restrictions
= mc
.Parent
.IsBaseType (p_parent
) &&
604 TypeManager
.IsThisOrFriendAssembly (Parent
.Module
.Assembly
, p
.Assembly
);
607 case Modifiers
.PRIVATE
:
609 // Both are private and share same parent
611 if (al
== Modifiers
.PRIVATE
) {
612 var decl
= mc
.Parent
;
614 same_access_restrictions
= TypeManager
.IsEqual (decl
.TypeBuilder
, p_parent
);
615 } while (!same_access_restrictions
&& !decl
.IsTopLevel
&& (decl
= decl
.Parent
) != null);
621 throw new InternalErrorException (al
.ToString ());
625 if (!same_access_restrictions
)
633 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
635 public override bool IsClsComplianceRequired ()
637 if ((caching_flags
& Flags
.ClsCompliance_Undetected
) == 0)
638 return (caching_flags
& Flags
.ClsCompliant
) != 0;
640 if (GetClsCompliantAttributeValue () && IsExposedFromAssembly ()) {
641 caching_flags
&= ~Flags
.ClsCompliance_Undetected
;
642 caching_flags
|= Flags
.ClsCompliant
;
646 caching_flags
&= ~Flags
.ClsCompliance_Undetected
;
651 /// Returns true when MemberCore is exposed from assembly.
653 public bool IsExposedFromAssembly ()
655 if ((ModFlags
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
658 DeclSpace parentContainer
= Parent
.PartialContainer
;
659 while (parentContainer
!= null && parentContainer
.ModFlags
!= 0) {
660 if ((parentContainer
.ModFlags
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
662 parentContainer
= parentContainer
.Parent
;
667 public virtual ExtensionMethodGroupExpr
LookupExtensionMethod (Type extensionType
, string name
, Location loc
)
669 return Parent
.LookupExtensionMethod (extensionType
, name
, loc
);
672 public virtual FullNamedExpression
LookupNamespaceAlias (string name
)
674 return Parent
.NamespaceEntry
.LookupNamespaceAlias (name
);
677 public virtual FullNamedExpression
LookupNamespaceOrType (string name
, Location loc
, bool ignore_cs0104
)
679 return Parent
.LookupNamespaceOrType (name
, loc
, ignore_cs0104
);
683 /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute.
684 /// If no is attribute exists then assembly CLSCompliantAttribute is returned.
686 public virtual bool GetClsCompliantAttributeValue ()
688 if ((caching_flags
& Flags
.HasCompliantAttribute_Undetected
) == 0)
689 return (caching_flags
& Flags
.ClsCompliantAttributeTrue
) != 0;
691 caching_flags
&= ~Flags
.HasCompliantAttribute_Undetected
;
693 if (OptAttributes
!= null) {
694 Attribute cls_attribute
= OptAttributes
.Search (
695 PredefinedAttributes
.Get
.CLSCompliant
);
696 if (cls_attribute
!= null) {
697 caching_flags
|= Flags
.HasClsCompliantAttribute
;
698 bool value = cls_attribute
.GetClsCompliantAttributeValue ();
700 caching_flags
|= Flags
.ClsCompliantAttributeTrue
;
705 // It's null for TypeParameter
709 if (Parent
.GetClsCompliantAttributeValue ()) {
710 caching_flags
|= Flags
.ClsCompliantAttributeTrue
;
717 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
719 protected bool HasClsCompliantAttribute
{
721 if ((caching_flags
& Flags
.HasCompliantAttribute_Undetected
) != 0)
722 GetClsCompliantAttributeValue ();
724 return (caching_flags
& Flags
.HasClsCompliantAttribute
) != 0;
729 /// Returns true when a member supports multiple overloads (methods, indexers, etc)
731 public virtual bool EnableOverloadChecks (MemberCore overload
)
737 /// The main virtual method for CLS-Compliant verifications.
738 /// The method returns true if member is CLS-Compliant and false if member is not
739 /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
740 /// and add their extra verifications.
742 protected virtual bool VerifyClsCompliance ()
744 if (!IsClsComplianceRequired ()) {
745 if (HasClsCompliantAttribute
&& Report
.WarningLevel
>= 2) {
746 if (!IsExposedFromAssembly ()) {
747 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
748 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 ());
751 if (!CodeGen
.Assembly
.IsClsCompliant
) {
752 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
753 Report
.Warning (3021, 2, a
.Location
, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ());
759 if (HasClsCompliantAttribute
) {
760 if (CodeGen
.Assembly
.ClsCompliantAttribute
== null && !CodeGen
.Assembly
.IsClsCompliant
) {
761 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
762 Report
.Warning (3014, 1, a
.Location
,
763 "`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant",
764 GetSignatureForError ());
768 if (!Parent
.IsClsComplianceRequired ()) {
769 Attribute a
= OptAttributes
.Search (PredefinedAttributes
.Get
.CLSCompliant
);
770 Report
.Warning (3018, 1, a
.Location
, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
771 GetSignatureForError (), Parent
.GetSignatureForError ());
776 if (member_name
.Name
[0] == '_') {
777 Report
.Warning (3008, 1, Location
, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
783 // Raised (and passed an XmlElement that contains the comment)
784 // when GenerateDocComment is writing documentation expectedly.
786 internal virtual void OnGenerateDocComment (XmlElement intermediateNode
)
791 // Returns a string that represents the signature for this
792 // member which should be used in XML documentation.
794 public virtual string GetDocCommentName (DeclSpace ds
)
796 if (ds
== null || this is DeclSpace
)
797 return DocCommentHeader
+ Name
;
799 return String
.Concat (DocCommentHeader
, ds
.Name
, ".", Name
);
803 // Generates xml doc comments (if any), and if required,
804 // handle warning report.
806 internal virtual void GenerateDocComment (DeclSpace ds
)
809 DocUtil
.GenerateDocComment (this, ds
, Report
);
810 } catch (Exception e
) {
811 throw new InternalErrorException (this, e
);
815 #region IMemberContext Members
817 public virtual CompilerContext Compiler
{
818 get { return Parent.Module.Compiler; }
821 public virtual Type CurrentType
{
822 get { return Parent.CurrentType; }
825 public virtual TypeContainer CurrentTypeDefinition
{
826 get { return Parent.CurrentTypeDefinition; }
829 public virtual TypeParameter
[] CurrentTypeParameters
{
833 public bool IsObsolete
{
835 if (GetObsoleteAttribute () != null)
838 return Parent
== null ? false : Parent
.IsObsolete
;
842 public bool IsUnsafe
{
844 if ((ModFlags
& Modifiers
.UNSAFE
) != 0)
847 return Parent
== null ? false : Parent
.IsUnsafe
;
851 public bool IsStatic
{
852 get { return (ModFlags & Modifiers.STATIC) != 0; }
859 // Base member specification. A member specification contains
860 // member details which can alter in the context (e.g. generic instances)
862 public abstract class MemberSpec
865 protected enum StateFlags
867 Obsolete_Undetected
= 1, // Obsolete attribute has not been detected yet
868 Obsolete
= 1 << 1 // Member has obsolete attribute
871 readonly Modifiers modifiers
;
872 readonly string name
;
873 protected StateFlags state
;
874 protected IMemberDefinition definition
;
875 public readonly MemberKind Kind
;
877 protected MemberSpec (MemberKind kind
, IMemberDefinition definition
, string name
, Modifiers modifiers
)
879 this.definition
= definition
;
881 this.modifiers
= modifiers
;
883 state
= StateFlags
.Obsolete_Undetected
;
886 public abstract Type DeclaringType { get; }
888 public ObsoleteAttribute
GetObsoleteAttribute ()
890 if ((state
& (StateFlags
.Obsolete
| StateFlags
.Obsolete_Undetected
)) == 0)
893 state
&= ~StateFlags
.Obsolete_Undetected
;
895 var oa
= definition
.GetObsoleteAttribute ();
897 state
|= StateFlags
.Obsolete
;
902 public IMemberDefinition MemberDefinition
{
903 get { return definition; }
906 public Modifiers Modifiers
{
907 get { return modifiers; }
914 public bool IsStatic
{
915 get { return (modifiers & Modifiers.STATIC) != 0; }
920 // Member details which are same between all member
923 public interface IMemberDefinition
925 ObsoleteAttribute
GetObsoleteAttribute ();
930 /// Base class for structs, classes, enumerations and interfaces.
933 /// They all create new declaration spaces. This
934 /// provides the common foundation for managing those name
937 public abstract class DeclSpace
: MemberCore
{
939 /// This points to the actual definition that is being
940 /// created with System.Reflection.Emit
942 public TypeBuilder TypeBuilder
;
945 /// If we are a generic type, this is the type we are
946 /// currently defining. We need to lookup members on this
947 /// instead of the TypeBuilder.
949 protected Type currentType
;
952 // This is the namespace in which this typecontainer
953 // was declared. We use this to resolve names.
955 public NamespaceEntry NamespaceEntry
;
957 private Dictionary
<string, FullNamedExpression
> Cache
= new Dictionary
<string, FullNamedExpression
> ();
959 public readonly string Basename
;
961 protected Dictionary
<string, MemberCore
> defined_names
;
963 public TypeContainer PartialContainer
;
965 protected readonly bool is_generic
;
966 readonly int count_type_params
;
967 protected TypeParameter
[] type_params
;
968 TypeParameter
[] type_param_list
;
971 // Whether we are Generic
973 public bool IsGeneric
{
977 else if (Parent
!= null)
978 return Parent
.IsGeneric
;
984 static string[] attribute_targets
= new string [] { "type" }
;
986 public DeclSpace (NamespaceEntry ns
, DeclSpace parent
, MemberName name
,
988 : base (parent
, name
, attrs
)
991 Basename
= name
.Basename
;
992 defined_names
= new Dictionary
<string, MemberCore
> ();
993 PartialContainer
= null;
994 if (name
.TypeArguments
!= null) {
996 count_type_params
= name
.TypeArguments
.Count
;
999 count_type_params
+= parent
.count_type_params
;
1003 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
1005 protected virtual bool AddToContainer (MemberCore symbol
, string name
)
1008 if (!defined_names
.TryGetValue (name
, out mc
)) {
1009 defined_names
.Add (name
, symbol
);
1013 if (((mc
.ModFlags
| symbol
.ModFlags
) & Modifiers
.COMPILER_GENERATED
) != 0)
1016 if (symbol
.EnableOverloadChecks (mc
))
1019 InterfaceMemberBase im
= mc
as InterfaceMemberBase
;
1020 if (im
!= null && im
.IsExplicitImpl
)
1023 Report
.SymbolRelatedToPreviousError (mc
);
1024 if ((mc
.ModFlags
& Modifiers
.PARTIAL
) != 0 && (symbol
is ClassOrStruct
|| symbol
is Interface
)) {
1025 Error_MissingPartialModifier (symbol
);
1029 if (this is ModuleContainer
) {
1030 Report
.Error (101, symbol
.Location
,
1031 "The namespace `{0}' already contains a definition for `{1}'",
1032 ((DeclSpace
)symbol
).NamespaceEntry
.GetSignatureForError (), symbol
.MemberName
.Name
);
1033 } else if (symbol
is TypeParameter
) {
1034 Report
.Error (692, symbol
.Location
,
1035 "Duplicate type parameter `{0}'", symbol
.GetSignatureForError ());
1037 Report
.Error (102, symbol
.Location
,
1038 "The type `{0}' already contains a definition for `{1}'",
1039 GetSignatureForError (), symbol
.MemberName
.Name
);
1045 protected void RemoveFromContainer (string name
)
1047 defined_names
.Remove (name
);
1051 /// Returns the MemberCore associated with a given name in the declaration
1052 /// space. It doesn't return method based symbols !!
1055 public MemberCore
GetDefinition (string name
)
1057 MemberCore mc
= null;
1058 defined_names
.TryGetValue (name
, out mc
);
1062 public bool IsStaticClass
{
1063 get { return (ModFlags & Modifiers.STATIC) != 0; }
1067 // root_types contains all the types. All TopLevel types
1068 // hence have a parent that points to `root_types', that is
1069 // why there is a non-obvious test down here.
1071 public bool IsTopLevel
{
1072 get { return (Parent != null && Parent.Parent == null); }
1075 public virtual bool IsUnmanagedType ()
1080 public virtual void CloseType ()
1082 if ((caching_flags
& Flags
.CloseTypeCreated
) == 0){
1084 TypeBuilder
.CreateType ();
1087 // The try/catch is needed because
1088 // nested enumerations fail to load when they
1091 // Even if this is the right order (enumerations
1092 // declared after types).
1094 // Note that this still creates the type and
1095 // it is possible to save it
1097 caching_flags
|= Flags
.CloseTypeCreated
;
1101 protected virtual TypeAttributes TypeAttr
{
1102 get { return Module.DefaultCharSetType; }
1106 /// Should be overriten by the appropriate declaration space
1108 public abstract TypeBuilder
DefineType ();
1110 protected void Error_MissingPartialModifier (MemberCore type
)
1112 Report
.Error (260, type
.Location
,
1113 "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists",
1114 type
.GetSignatureForError ());
1117 public override void Emit ()
1119 if (type_params
!= null) {
1120 int offset
= count_type_params
- type_params
.Length
;
1121 for (int i
= offset
; i
< type_params
.Length
; i
++)
1122 CurrentTypeParameters
[i
- offset
].Emit ();
1125 if ((ModFlags
& Modifiers
.COMPILER_GENERATED
) != 0 && !Parent
.IsCompilerGenerated
)
1126 PredefinedAttributes
.Get
.CompilerGenerated
.EmitAttribute (TypeBuilder
);
1131 public override string GetSignatureForError ()
1133 return MemberName
.GetSignatureForError ();
1136 public bool CheckAccessLevel (Type check_type
)
1138 Type tb
= TypeBuilder
;
1140 if (this is GenericMethod
) {
1141 tb
= Parent
.TypeBuilder
;
1143 // FIXME: Generic container does not work with nested generic
1144 // anonymous method stories
1145 if (TypeBuilder
== null)
1149 check_type
= TypeManager
.DropGenericTypeArguments (check_type
);
1150 if (check_type
== tb
)
1153 // TODO: When called from LocalUsingAliasEntry tb is null
1154 // because we are in RootDeclSpace
1156 tb
= typeof (RootDeclSpace
);
1159 // Broken Microsoft runtime, return public for arrays, no matter what
1160 // the accessibility is for their underlying class, and they return
1161 // NonPublic visibility for pointers
1163 if (TypeManager
.HasElementType (check_type
))
1164 return CheckAccessLevel (TypeManager
.GetElementType (check_type
));
1166 if (TypeManager
.IsGenericParameter (check_type
))
1169 TypeAttributes check_attr
= check_type
.Attributes
& TypeAttributes
.VisibilityMask
;
1171 switch (check_attr
){
1172 case TypeAttributes
.Public
:
1175 case TypeAttributes
.NotPublic
:
1176 return TypeManager
.IsThisOrFriendAssembly (Module
.Assembly
, check_type
.Assembly
);
1178 case TypeAttributes
.NestedPublic
:
1179 return CheckAccessLevel (check_type
.DeclaringType
);
1181 case TypeAttributes
.NestedPrivate
:
1182 Type declaring
= check_type
.DeclaringType
;
1183 return tb
== declaring
|| TypeManager
.IsNestedChildOf (tb
, declaring
);
1185 case TypeAttributes
.NestedFamily
:
1187 // Only accessible to methods in current type or any subtypes
1189 return FamilyAccessible (tb
, check_type
);
1191 case TypeAttributes
.NestedFamANDAssem
:
1192 return TypeManager
.IsThisOrFriendAssembly (Module
.Assembly
, check_type
.Assembly
) &&
1193 FamilyAccessible (tb
, check_type
);
1195 case TypeAttributes
.NestedFamORAssem
:
1196 return FamilyAccessible (tb
, check_type
) ||
1197 TypeManager
.IsThisOrFriendAssembly (Module
.Assembly
, check_type
.Assembly
);
1199 case TypeAttributes
.NestedAssembly
:
1200 return TypeManager
.IsThisOrFriendAssembly (Module
.Assembly
, check_type
.Assembly
);
1203 throw new NotImplementedException (check_attr
.ToString ());
1206 static bool FamilyAccessible (Type tb
, Type check_type
)
1208 Type declaring
= check_type
.DeclaringType
;
1209 return TypeManager
.IsNestedFamilyAccessible (tb
, declaring
);
1212 public bool IsBaseType (Type baseType
)
1214 // We are called from RootDeclspace
1215 if (TypeBuilder
== null)
1218 return TypeManager
.IsSubclassOf (TypeBuilder
, baseType
);
1221 private Type
LookupNestedTypeInHierarchy (string name
)
1224 // if the member cache has been created, lets use it.
1225 // the member cache is MUCH faster.
1226 if (MemberCache
!= null) {
1227 t
= MemberCache
.FindNestedType (name
);
1233 // FIXME: This hack is needed because member cache does not work
1234 // with nested base generic types, it does only type name copy and
1235 // not type construction
1238 // no member cache. Do it the hard way -- reflection
1239 for (Type current_type
= TypeBuilder
;
1240 current_type
!= null && current_type
!= TypeManager
.object_type
;
1241 current_type
= current_type
.BaseType
) {
1243 Type ct
= TypeManager
.DropGenericTypeArguments (current_type
);
1244 if (ct
is TypeBuilder
) {
1245 TypeContainer tc
= ct
== TypeBuilder
1246 ? PartialContainer
: TypeManager
.LookupTypeContainer (ct
);
1248 t
= tc
.FindNestedType (name
);
1250 t
= TypeManager
.GetNestedType (ct
, name
);
1253 if ((t
== null) || !CheckAccessLevel (t
))
1256 if (!TypeManager
.IsGenericType (current_type
))
1259 Type
[] args
= TypeManager
.GetTypeArguments (current_type
);
1260 Type
[] targs
= TypeManager
.GetTypeArguments (t
);
1261 for (int i
= 0; i
< args
.Length
; i
++)
1262 targs
[i
] = TypeManager
.TypeToCoreType (args
[i
]);
1264 return t
.MakeGenericType (targs
);
1271 // Public function used to locate types.
1273 // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
1275 // Returns: Type or null if they type can not be found.
1277 public override FullNamedExpression
LookupNamespaceOrType (string name
, Location loc
, bool ignore_cs0104
)
1279 FullNamedExpression e
;
1280 if (Cache
.TryGetValue (name
, out e
))
1284 int errors
= Report
.Errors
;
1286 TypeParameter
[] tp
= CurrentTypeParameters
;
1288 TypeParameter tparam
= TypeParameter
.FindTypeParameter (tp
, name
);
1290 e
= new TypeParameterExpr (tparam
, Location
.Null
);
1294 Type t
= LookupNestedTypeInHierarchy (name
);
1297 e
= new TypeExpression (t
, Location
.Null
);
1298 else if (Parent
!= null)
1299 e
= Parent
.LookupNamespaceOrType (name
, loc
, ignore_cs0104
);
1301 e
= NamespaceEntry
.LookupNamespaceOrType (name
, loc
, ignore_cs0104
);
1304 if (errors
== Report
.Errors
)
1311 /// This function is broken and not what you're looking for. It should only
1312 /// be used while the type is still being created since it doesn't use the cache
1313 /// and relies on the filter doing the member name check.
1316 // [Obsolete ("Only MemberCache approach should be used")]
1317 public virtual MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
1318 MemberFilter filter
, object criteria
)
1320 throw new NotSupportedException ();
1324 /// If we have a MemberCache, return it. This property may return null if the
1325 /// class doesn't have a member cache or while it's still being created.
1327 public abstract MemberCache MemberCache
{
1331 public virtual ModuleContainer Module
{
1332 get { return Parent.Module; }
1335 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
, PredefinedAttributes pa
)
1337 if (a
.Type
== pa
.Required
) {
1338 Report
.Error (1608, a
.Location
, "The RequiredAttribute attribute is not permitted on C# types");
1341 TypeBuilder
.SetCustomAttribute (cb
);
1344 TypeParameter
[] initialize_type_params ()
1346 if (type_param_list
!= null)
1347 return type_param_list
;
1349 DeclSpace the_parent
= Parent
;
1350 if (this is GenericMethod
)
1353 var list
= new List
<TypeParameter
> ();
1354 if (the_parent
!= null && the_parent
.IsGeneric
) {
1355 // FIXME: move generics info out of DeclSpace
1356 TypeParameter
[] parent_params
= the_parent
.TypeParameters
;
1357 list
.AddRange (parent_params
);
1360 int count
= type_params
!= null ? type_params
.Length
: 0;
1361 for (int i
= 0; i
< count
; i
++) {
1362 TypeParameter param
= type_params
[i
];
1364 if (Parent
.CurrentTypeParameters
!= null) {
1365 foreach (TypeParameter tp
in Parent
.CurrentTypeParameters
) {
1366 if (tp
.Name
!= param
.Name
)
1369 Report
.SymbolRelatedToPreviousError (tp
.Location
, null);
1370 Report
.Warning (693, 3, param
.Location
,
1371 "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
1372 param
.Name
, Parent
.GetSignatureForError ());
1377 type_param_list
= new TypeParameter
[list
.Count
];
1378 list
.CopyTo (type_param_list
, 0);
1379 return type_param_list
;
1382 public virtual void SetParameterInfo (List
<Constraints
> constraints_list
)
1385 if (constraints_list
!= null) {
1387 80, Location
, "Constraints are not allowed " +
1388 "on non-generic declarations");
1394 TypeParameterName
[] names
= MemberName
.TypeArguments
.GetDeclarations ();
1395 type_params
= new TypeParameter
[names
.Length
];
1398 // Register all the names
1400 for (int i
= 0; i
< type_params
.Length
; i
++) {
1401 TypeParameterName name
= names
[i
];
1403 Constraints constraints
= null;
1404 if (constraints_list
!= null) {
1405 int total
= constraints_list
.Count
;
1406 for (int ii
= 0; ii
< total
; ++ii
) {
1407 Constraints constraints_at
= (Constraints
)constraints_list
[ii
];
1408 // TODO: it is used by iterators only
1409 if (constraints_at
== null) {
1410 constraints_list
.RemoveAt (ii
);
1414 if (constraints_at
.TypeParameter
.Value
== name
.Name
) {
1415 constraints
= constraints_at
;
1416 constraints_list
.RemoveAt(ii
);
1422 Variance variance
= name
.Variance
;
1423 if (name
.Variance
!= Variance
.None
&& !(this is Delegate
|| this is Interface
)) {
1424 Report
.Error (1960, name
.Location
, "Variant type parameters can only be used with interfaces and delegates");
1425 variance
= Variance
.None
;
1428 type_params
[i
] = new TypeParameter (
1429 Parent
, this, name
.Name
, constraints
, name
.OptAttributes
, variance
, Location
);
1431 AddToContainer (type_params
[i
], name
.Name
);
1434 if (constraints_list
!= null && constraints_list
.Count
> 0) {
1435 foreach (Constraints constraint
in constraints_list
) {
1436 Report
.Error(699, constraint
.Location
, "`{0}': A constraint references nonexistent type parameter `{1}'",
1437 GetSignatureForError (), constraint
.TypeParameter
.Value
);
1442 public TypeParameter
[] TypeParameters
{
1445 throw new InvalidOperationException ();
1446 if ((PartialContainer
!= null) && (PartialContainer
!= this))
1447 return PartialContainer
.TypeParameters
;
1448 if (type_param_list
== null)
1449 initialize_type_params ();
1451 return type_param_list
;
1455 public override Type CurrentType
{
1456 get { return currentType != null ? currentType : TypeBuilder; }
1459 public override TypeContainer CurrentTypeDefinition
{
1460 get { return PartialContainer; }
1463 public int CountTypeParameters
{
1465 return count_type_params
;
1469 // Used for error reporting only
1470 public virtual Type
LookupAnyGeneric (string typeName
)
1472 return NamespaceEntry
.NS
.LookForAnyGenericType (typeName
);
1475 public override string[] ValidAttributeTargets
{
1476 get { return attribute_targets; }
1479 protected override bool VerifyClsCompliance ()
1481 if (!base.VerifyClsCompliance ()) {
1485 if (type_params
!= null) {
1486 foreach (TypeParameter tp
in type_params
) {
1487 if (tp
.Constraints
== null)
1490 tp
.Constraints
.VerifyClsCompliance (Report
);
1494 var cache
= TypeManager
.AllClsTopLevelTypes
;
1498 string lcase
= Name
.ToLower (System
.Globalization
.CultureInfo
.InvariantCulture
);
1499 if (!cache
.ContainsKey (lcase
)) {
1500 cache
.Add (lcase
, this);
1504 object val
= cache
[lcase
];
1506 Type t
= AttributeTester
.GetImportedIgnoreCaseClsType (lcase
);
1509 Report
.SymbolRelatedToPreviousError (t
);
1512 Report
.SymbolRelatedToPreviousError ((DeclSpace
)val
);
1515 Report
.Warning (3005, 1, Location
, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());