2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / decl.cs
blob0eacc8239ba7200f0d32fd65e9635f666f8ec968
1 //
2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@seznam.cz)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2004-2008 Novell, Inc
14 using System;
15 using System.Text;
16 using System.Collections.Generic;
17 using System.Globalization;
18 using System.Reflection.Emit;
19 using System.Reflection;
21 #if NET_2_1
22 using XmlElement = System.Object;
23 #else
24 using System.Xml;
25 #endif
27 namespace Mono.CSharp {
30 // Better name would be DottenName
32 public class MemberName {
33 public readonly string Name;
34 public readonly TypeArguments TypeArguments;
36 public readonly MemberName Left;
37 public readonly Location Location;
39 public static readonly MemberName Null = new MemberName ("");
41 bool is_double_colon;
43 private MemberName (MemberName left, string name, bool is_double_colon,
44 Location loc)
46 this.Name = name;
47 this.Location = loc;
48 this.is_double_colon = is_double_colon;
49 this.Left = left;
52 private MemberName (MemberName left, string name, bool is_double_colon,
53 TypeArguments args, Location loc)
54 : this (left, name, is_double_colon, loc)
56 if (args != null && args.Count > 0)
57 this.TypeArguments = args;
60 public MemberName (string name)
61 : this (name, Location.Null)
62 { }
64 public MemberName (string name, Location loc)
65 : this (null, name, false, loc)
66 { }
68 public MemberName (string name, TypeArguments args, Location loc)
69 : this (null, name, false, args, loc)
70 { }
72 public MemberName (MemberName left, string name)
73 : this (left, name, left != null ? left.Location : Location.Null)
74 { }
76 public MemberName (MemberName left, string name, Location loc)
77 : this (left, name, false, loc)
78 { }
80 public MemberName (MemberName left, string name, TypeArguments args, Location loc)
81 : this (left, name, false, args, loc)
82 { }
84 public MemberName (string alias, string name, TypeArguments args, Location loc)
85 : this (new MemberName (alias, loc), name, true, args, loc)
86 { }
88 public MemberName (MemberName left, MemberName right)
89 : this (left, right, right.Location)
90 { }
92 public MemberName (MemberName left, MemberName right, Location loc)
93 : this (null, right.Name, false, right.TypeArguments, loc)
95 if (right.is_double_colon)
96 throw new InternalErrorException ("Cannot append double_colon member name");
97 this.Left = (right.Left == null) ? left : new MemberName (left, right.Left);
100 // TODO: Remove
101 public string GetName ()
103 return GetName (false);
106 public bool IsGeneric {
107 get {
108 if (TypeArguments != null)
109 return true;
110 else if (Left != null)
111 return Left.IsGeneric;
112 else
113 return false;
117 public string GetName (bool is_generic)
119 string name = is_generic ? Basename : Name;
120 if (Left != null)
121 return Left.GetName (is_generic) + (is_double_colon ? "::" : ".") + name;
123 return name;
126 public ATypeNameExpression GetTypeExpression ()
128 if (Left == null) {
129 if (TypeArguments != null)
130 return new SimpleName (Basename, TypeArguments, Location);
132 return new SimpleName (Name, Location);
135 if (is_double_colon) {
136 if (Left.Left != null)
137 throw new InternalErrorException ("The left side of a :: should be an identifier");
138 return new QualifiedAliasMember (Left.Name, Name, TypeArguments, Location);
141 Expression lexpr = Left.GetTypeExpression ();
142 return new MemberAccess (lexpr, Name, TypeArguments, Location);
145 public MemberName Clone ()
147 MemberName left_clone = Left == null ? null : Left.Clone ();
148 return new MemberName (left_clone, Name, is_double_colon, TypeArguments, Location);
151 public string Basename {
152 get {
153 if (TypeArguments != null)
154 return MakeName (Name, TypeArguments);
155 return Name;
159 public string GetSignatureForError ()
161 string append = TypeArguments == null ? "" : "<" + TypeArguments.GetSignatureForError () + ">";
162 if (Left == null)
163 return Name + append;
164 string connect = is_double_colon ? "::" : ".";
165 return Left.GetSignatureForError () + connect + Name + append;
168 public override bool Equals (object other)
170 return Equals (other as MemberName);
173 public bool Equals (MemberName other)
175 if (this == other)
176 return true;
177 if (other == null || Name != other.Name)
178 return false;
179 if (is_double_colon != other.is_double_colon)
180 return false;
182 if ((TypeArguments != null) &&
183 (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count))
184 return false;
186 if ((TypeArguments == null) && (other.TypeArguments != null))
187 return false;
189 if (Left == null)
190 return other.Left == null;
192 return Left.Equals (other.Left);
195 public override int GetHashCode ()
197 int hash = Name.GetHashCode ();
198 for (MemberName n = Left; n != null; n = n.Left)
199 hash ^= n.Name.GetHashCode ();
200 if (is_double_colon)
201 hash ^= 0xbadc01d;
203 if (TypeArguments != null)
204 hash ^= TypeArguments.Count << 5;
206 return hash & 0x7FFFFFFF;
209 public int CountTypeArguments {
210 get {
211 if (TypeArguments != null)
212 return TypeArguments.Count;
213 else if (Left != null)
214 return Left.CountTypeArguments;
215 else
216 return 0;
220 public static string MakeName (string name, TypeArguments args)
222 if (args == null)
223 return name;
225 return name + "`" + args.Count;
228 public static string MakeName (string name, int count)
230 return name + "`" + count;
234 public class SimpleMemberName
236 public string Value;
237 public Location Location;
239 public SimpleMemberName (string name, Location loc)
241 this.Value = name;
242 this.Location = loc;
246 /// <summary>
247 /// Base representation for members. This is used to keep track
248 /// of Name, Location and Modifier flags, and handling Attributes.
249 /// </summary>
250 public abstract class MemberCore : Attributable, IMemberContext, IMemberDefinition
252 /// <summary>
253 /// Public name
254 /// </summary>
256 protected string cached_name;
257 // TODO: Remove in favor of MemberName
258 public string Name {
259 get {
260 if (cached_name == null)
261 cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method));
262 return cached_name;
266 // Is not readonly because of IndexerName attribute
267 private MemberName member_name;
268 public MemberName MemberName {
269 get { return member_name; }
272 /// <summary>
273 /// Modifier flags that the user specified in the source code
274 /// </summary>
275 private Modifiers mod_flags;
276 public Modifiers ModFlags {
277 set {
278 mod_flags = value;
279 if ((value & Modifiers.COMPILER_GENERATED) != 0)
280 caching_flags = Flags.IsUsed | Flags.IsAssigned;
282 get {
283 return mod_flags;
287 public /*readonly*/ DeclSpace Parent;
289 /// <summary>
290 /// Location where this declaration happens
291 /// </summary>
292 public Location Location {
293 get { return member_name.Location; }
296 /// <summary>
297 /// XML documentation comment
298 /// </summary>
299 protected string comment;
301 /// <summary>
302 /// Represents header string for documentation comment
303 /// for each member types.
304 /// </summary>
305 public abstract string DocCommentHeader { get; }
307 [Flags]
308 public enum Flags {
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
320 IsUsed = 1 << 11,
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
327 /// <summary>
328 /// MemberCore flags at first detected then cached
329 /// </summary>
330 internal Flags caching_flags;
332 public MemberCore (DeclSpace parent, MemberName name, Attributes attrs)
334 this.Parent = parent;
335 member_name = name;
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;
343 cached_name = null;
346 protected bool CheckAbstractAndExtern (bool has_block)
348 if (Parent.PartialContainer.Kind == MemberKind.Interface)
349 return true;
351 if (has_block) {
352 if ((ModFlags & Modifiers.EXTERN) != 0) {
353 Report.Error (179, Location, "`{0}' cannot declare a body because it is marked extern",
354 GetSignatureForError ());
355 return false;
358 if ((ModFlags & Modifiers.ABSTRACT) != 0) {
359 Report.Error (500, Location, "`{0}' cannot declare a body because it is marked abstract",
360 GetSignatureForError ());
361 return false;
363 } else {
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)
368 pm = null;
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 ());
374 return false;
378 Report.Error (501, Location, "`{0}' must have a body because it is not marked abstract, extern, or partial",
379 GetSignatureForError ());
380 return false;
384 return true;
387 protected void CheckProtectedModifier ()
389 if ((ModFlags & Modifiers.PROTECTED) == 0)
390 return;
392 if (Parent.PartialContainer.Kind == MemberKind.Struct) {
393 Report.Error (666, Location, "`{0}': Structs cannot contain protected members",
394 GetSignatureForError ());
395 return;
398 if ((Parent.ModFlags & Modifiers.STATIC) != 0) {
399 Report.Error (1057, Location, "`{0}': Static classes cannot contain protected members",
400 GetSignatureForError ());
401 return;
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 ());
408 return;
412 public abstract bool Define ();
414 public virtual string DocComment {
415 get {
416 return comment;
418 set {
419 comment = value;
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 ();
434 /// <summary>
435 /// Base Emit method. This is also entry point for CLS-Compliant verification.
436 /// </summary>
437 public virtual void Emit ()
439 if (!RootContext.VerifyClsCompliance)
440 return;
442 if (Report.WarningLevel > 0)
443 VerifyClsCompliance ();
446 public bool IsCompilerGenerated {
447 get {
448 if ((mod_flags & Modifiers.COMPILER_GENERATED) != 0)
449 return true;
451 return Parent == null ? false : Parent.IsCompilerGenerated;
455 public virtual bool IsUsed {
456 get { return (caching_flags & Flags.IsUsed) != 0; }
459 protected Report Report {
460 get {
461 return Compiler.Report;
465 public void SetIsUsed ()
467 caching_flags |= Flags.IsUsed;
470 /// <summary>
471 /// Returns instance of ObsoleteAttribute for this MemberCore
472 /// </summary>
473 public virtual ObsoleteAttribute GetObsoleteAttribute ()
475 if ((caching_flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0)
476 return null;
478 caching_flags &= ~Flags.Obsolete_Undetected;
480 if (OptAttributes == null)
481 return null;
483 Attribute obsolete_attr = OptAttributes.Search (PredefinedAttributes.Get.Obsolete);
484 if (obsolete_attr == null)
485 return null;
487 caching_flags |= Flags.Obsolete;
489 ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute ();
490 if (obsolete == null)
491 return null;
493 return obsolete;
496 /// <summary>
497 /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
498 /// </summary>
499 public virtual void CheckObsoleteness (Location loc)
501 ObsoleteAttribute oa = GetObsoleteAttribute ();
502 if (oa != null)
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;
512 Modifiers mod;
513 switch (ma & TypeAttributes.VisibilityMask) {
514 case TypeAttributes.Public:
515 case TypeAttributes.NestedPublic:
516 mod = Modifiers.PUBLIC;
517 break;
518 case TypeAttributes.NestedPrivate:
519 mod = Modifiers.PRIVATE;
520 break;
521 case TypeAttributes.NestedFamily:
522 mod = Modifiers.PROTECTED;
523 break;
524 case TypeAttributes.NestedFamORAssem:
525 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
526 break;
527 default:
528 mod = Modifiers.INTERNAL;
529 break;
532 return mod;
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
543 // may return true.
545 if ((mod_flags & Modifiers.PRIVATE) != 0)
546 return true;
548 while (TypeManager.HasElementType (p))
549 p = TypeManager.GetElementType (p);
551 if (TypeManager.IsGenericParameter (p))
552 return true;
554 if (TypeManager.IsGenericType (p)) {
555 foreach (Type t in TypeManager.GetTypeArguments (p)) {
556 if (!IsAccessibleAs (t))
557 return false;
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)
565 continue;
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;
570 switch (pAccess) {
571 case Modifiers.INTERNAL:
572 if (al == Modifiers.PRIVATE || al == Modifiers.INTERNAL)
573 same_access_restrictions = TypeManager.IsThisOrFriendAssembly (Parent.Module.Assembly, p.Assembly);
575 break;
577 case Modifiers.PROTECTED:
578 if (al == Modifiers.PROTECTED) {
579 same_access_restrictions = mc.Parent.IsBaseType (p_parent);
580 break;
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;
591 mc = mc.Parent;
595 break;
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);
605 break;
607 case Modifiers.PRIVATE:
609 // Both are private and share same parent
611 if (al == Modifiers.PRIVATE) {
612 var decl = mc.Parent;
613 do {
614 same_access_restrictions = TypeManager.IsEqual (decl.TypeBuilder, p_parent);
615 } while (!same_access_restrictions && !decl.IsTopLevel && (decl = decl.Parent) != null);
618 break;
620 default:
621 throw new InternalErrorException (al.ToString ());
625 if (!same_access_restrictions)
626 return false;
629 return true;
632 /// <summary>
633 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
634 /// </summary>
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;
643 return true;
646 caching_flags &= ~Flags.ClsCompliance_Undetected;
647 return false;
650 /// <summary>
651 /// Returns true when MemberCore is exposed from assembly.
652 /// </summary>
653 public bool IsExposedFromAssembly ()
655 if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
656 return false;
658 DeclSpace parentContainer = Parent.PartialContainer;
659 while (parentContainer != null && parentContainer.ModFlags != 0) {
660 if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
661 return false;
662 parentContainer = parentContainer.Parent;
664 return true;
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);
682 /// <summary>
683 /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute.
684 /// If no is attribute exists then assembly CLSCompliantAttribute is returned.
685 /// </summary>
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 ();
699 if (value)
700 caching_flags |= Flags.ClsCompliantAttributeTrue;
701 return value;
705 // It's null for TypeParameter
706 if (Parent == null)
707 return false;
709 if (Parent.GetClsCompliantAttributeValue ()) {
710 caching_flags |= Flags.ClsCompliantAttributeTrue;
711 return true;
713 return false;
716 /// <summary>
717 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
718 /// </summary>
719 protected bool HasClsCompliantAttribute {
720 get {
721 if ((caching_flags & Flags.HasCompliantAttribute_Undetected) != 0)
722 GetClsCompliantAttributeValue ();
724 return (caching_flags & Flags.HasClsCompliantAttribute) != 0;
728 /// <summary>
729 /// Returns true when a member supports multiple overloads (methods, indexers, etc)
730 /// </summary>
731 public virtual bool EnableOverloadChecks (MemberCore overload)
733 return false;
736 /// <summary>
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.
741 /// </summary>
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 ());
756 return false;
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 ());
765 return false;
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 ());
772 return false;
776 if (member_name.Name [0] == '_') {
777 Report.Warning (3008, 1, Location, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
779 return true;
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;
798 else
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)
808 try {
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 {
830 get { return null; }
833 public bool IsObsolete {
834 get {
835 if (GetObsoleteAttribute () != null)
836 return true;
838 return Parent == null ? false : Parent.IsObsolete;
842 public bool IsUnsafe {
843 get {
844 if ((ModFlags & Modifiers.UNSAFE) != 0)
845 return true;
847 return Parent == null ? false : Parent.IsUnsafe;
851 public bool IsStatic {
852 get { return (ModFlags & Modifiers.STATIC) != 0; }
855 #endregion
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
864 [Flags]
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;
880 this.name = name;
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)
891 return null;
893 state &= ~StateFlags.Obsolete_Undetected;
895 var oa = definition.GetObsoleteAttribute ();
896 if (oa != null)
897 state |= StateFlags.Obsolete;
899 return oa;
902 public IMemberDefinition MemberDefinition {
903 get { return definition; }
906 public Modifiers Modifiers {
907 get { return modifiers; }
910 public string Name {
911 get { return name; }
914 public bool IsStatic {
915 get { return (modifiers & Modifiers.STATIC) != 0; }
920 // Member details which are same between all member
921 // specifications
923 public interface IMemberDefinition
925 ObsoleteAttribute GetObsoleteAttribute ();
926 void SetIsUsed ();
929 /// <summary>
930 /// Base class for structs, classes, enumerations and interfaces.
931 /// </summary>
932 /// <remarks>
933 /// They all create new declaration spaces. This
934 /// provides the common foundation for managing those name
935 /// spaces.
936 /// </remarks>
937 public abstract class DeclSpace : MemberCore {
938 /// <summary>
939 /// This points to the actual definition that is being
940 /// created with System.Reflection.Emit
941 /// </summary>
942 public TypeBuilder TypeBuilder;
944 /// <summary>
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.
948 /// </summary>
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 {
974 get {
975 if (is_generic)
976 return true;
977 else if (Parent != null)
978 return Parent.IsGeneric;
979 else
980 return false;
984 static string[] attribute_targets = new string [] { "type" };
986 public DeclSpace (NamespaceEntry ns, DeclSpace parent, MemberName name,
987 Attributes attrs)
988 : base (parent, name, attrs)
990 NamespaceEntry = ns;
991 Basename = name.Basename;
992 defined_names = new Dictionary<string, MemberCore> ();
993 PartialContainer = null;
994 if (name.TypeArguments != null) {
995 is_generic = true;
996 count_type_params = name.TypeArguments.Count;
998 if (parent != null)
999 count_type_params += parent.count_type_params;
1002 /// <summary>
1003 /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
1004 /// </summary>
1005 protected virtual bool AddToContainer (MemberCore symbol, string name)
1007 MemberCore mc;
1008 if (!defined_names.TryGetValue (name, out mc)) {
1009 defined_names.Add (name, symbol);
1010 return true;
1013 if (((mc.ModFlags | symbol.ModFlags) & Modifiers.COMPILER_GENERATED) != 0)
1014 return true;
1016 if (symbol.EnableOverloadChecks (mc))
1017 return true;
1019 InterfaceMemberBase im = mc as InterfaceMemberBase;
1020 if (im != null && im.IsExplicitImpl)
1021 return true;
1023 Report.SymbolRelatedToPreviousError (mc);
1024 if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (symbol is ClassOrStruct || symbol is Interface)) {
1025 Error_MissingPartialModifier (symbol);
1026 return false;
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 ());
1036 } else {
1037 Report.Error (102, symbol.Location,
1038 "The type `{0}' already contains a definition for `{1}'",
1039 GetSignatureForError (), symbol.MemberName.Name);
1042 return false;
1045 protected void RemoveFromContainer (string name)
1047 defined_names.Remove (name);
1050 /// <summary>
1051 /// Returns the MemberCore associated with a given name in the declaration
1052 /// space. It doesn't return method based symbols !!
1053 /// </summary>
1054 ///
1055 public MemberCore GetDefinition (string name)
1057 MemberCore mc = null;
1058 defined_names.TryGetValue (name, out mc);
1059 return 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 ()
1077 return false;
1080 public virtual void CloseType ()
1082 if ((caching_flags & Flags.CloseTypeCreated) == 0){
1083 try {
1084 TypeBuilder.CreateType ();
1085 } catch {
1087 // The try/catch is needed because
1088 // nested enumerations fail to load when they
1089 // are defined.
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; }
1105 /// <remarks>
1106 /// Should be overriten by the appropriate declaration space
1107 /// </remarks>
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);
1128 base.Emit ();
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)
1146 return true;
1149 check_type = TypeManager.DropGenericTypeArguments (check_type);
1150 if (check_type == tb)
1151 return true;
1153 // TODO: When called from LocalUsingAliasEntry tb is null
1154 // because we are in RootDeclSpace
1155 if (tb == null)
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))
1167 return true;
1169 TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
1171 switch (check_attr){
1172 case TypeAttributes.Public:
1173 return true;
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)
1216 return false;
1218 return TypeManager.IsSubclassOf (TypeBuilder, baseType);
1221 private Type LookupNestedTypeInHierarchy (string name)
1223 Type t = null;
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);
1228 if (t == null)
1229 return null;
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);
1247 if (tc != null)
1248 t = tc.FindNestedType (name);
1249 } else {
1250 t = TypeManager.GetNestedType (ct, name);
1253 if ((t == null) || !CheckAccessLevel (t))
1254 continue;
1256 if (!TypeManager.IsGenericType (current_type))
1257 return t;
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);
1267 return null;
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))
1281 return e;
1283 e = null;
1284 int errors = Report.Errors;
1286 TypeParameter[] tp = CurrentTypeParameters;
1287 if (tp != null) {
1288 TypeParameter tparam = TypeParameter.FindTypeParameter (tp, name);
1289 if (tparam != null)
1290 e = new TypeParameterExpr (tparam, Location.Null);
1293 if (e == null) {
1294 Type t = LookupNestedTypeInHierarchy (name);
1296 if (t != null)
1297 e = new TypeExpression (t, Location.Null);
1298 else if (Parent != null)
1299 e = Parent.LookupNamespaceOrType (name, loc, ignore_cs0104);
1300 else
1301 e = NamespaceEntry.LookupNamespaceOrType (name, loc, ignore_cs0104);
1304 if (errors == Report.Errors)
1305 Cache [name] = e;
1307 return e;
1310 /// <remarks>
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.
1314 /// </remarks>
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 ();
1323 /// <remarks>
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.
1326 /// </remarks>
1327 public abstract MemberCache MemberCache {
1328 get;
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");
1339 return;
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)
1351 the_parent = null;
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];
1363 list.Add (param);
1364 if (Parent.CurrentTypeParameters != null) {
1365 foreach (TypeParameter tp in Parent.CurrentTypeParameters) {
1366 if (tp.Name != param.Name)
1367 continue;
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)
1384 if (!is_generic) {
1385 if (constraints_list != null) {
1386 Report.Error (
1387 80, Location, "Constraints are not allowed " +
1388 "on non-generic declarations");
1391 return;
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);
1411 --total;
1412 continue;
1414 if (constraints_at.TypeParameter.Value == name.Name) {
1415 constraints = constraints_at;
1416 constraints_list.RemoveAt(ii);
1417 break;
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 {
1443 get {
1444 if (!IsGeneric)
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 {
1464 get {
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 ()) {
1482 return false;
1485 if (type_params != null) {
1486 foreach (TypeParameter tp in type_params) {
1487 if (tp.Constraints == null)
1488 continue;
1490 tp.Constraints.VerifyClsCompliance (Report);
1494 var cache = TypeManager.AllClsTopLevelTypes;
1495 if (cache == null)
1496 return true;
1498 string lcase = Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
1499 if (!cache.ContainsKey (lcase)) {
1500 cache.Add (lcase, this);
1501 return true;
1504 object val = cache [lcase];
1505 if (val == null) {
1506 Type t = AttributeTester.GetImportedIgnoreCaseClsType (lcase);
1507 if (t == null)
1508 return true;
1509 Report.SymbolRelatedToPreviousError (t);
1511 else {
1512 Report.SymbolRelatedToPreviousError ((DeclSpace)val);
1515 Report.Warning (3005, 1, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
1516 return true;