2 // enum.cs: Enum handling.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Licensed under the terms of the GNU GPL
10 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Globalization;
21 namespace Mono.CSharp {
23 public class EnumMember: MemberCore, IConstant {
24 static string[] attribute_targets = new string [] { "field" };
26 public FieldBuilder builder;
28 readonly Enum parent_enum;
29 readonly Expression ValueExpr;
30 readonly EnumMember prev_member;
35 public EnumMember (Enum parent_enum, EnumMember prev_member, Expression expr,
36 MemberName name, Attributes attrs):
37 base (parent_enum.Parent, name, attrs)
39 this.parent_enum = parent_enum;
40 this.ModFlags = parent_enum.ModFlags;
41 this.ValueExpr = expr;
42 this.prev_member = prev_member;
45 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
47 if (a.Type == TypeManager.marshal_as_attr_type) {
48 UnmanagedMarshal marshal = a.GetMarshal (this);
49 if (marshal != null) {
50 builder.SetMarshal (marshal);
55 if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
56 a.Error_InvalidSecurityParent ();
60 builder.SetCustomAttribute (cb);
63 public override AttributeTargets AttributeTargets {
65 return AttributeTargets.Field;
69 bool IsValidEnumType (Type t)
71 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
72 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
73 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
77 public override bool Define ()
79 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
80 TypeBuilder tb = parent_enum.TypeBuilder;
81 builder = tb.DefineField (Name, tb, attr);
83 TypeManager.RegisterConstant (builder, this);
87 // Because parent is TypeContainer and we have DeclSpace only
88 public override void CheckObsoleteness (Location loc)
90 parent_enum.CheckObsoleteness (loc);
92 ObsoleteAttribute oa = GetObsoleteAttribute ();
97 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
100 public bool ResolveValue ()
106 // suppress cyclic errors
107 value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
108 Const.Error_CyclicDeclaration (this);
112 if (ValueExpr != null) {
114 Constant c = ValueExpr.ResolveAsConstant (parent_enum.EmitContext, this);
120 if (c is EnumConstant)
121 c = ((EnumConstant)c).Child;
123 c = c.ToType (parent_enum.UnderlyingType, Location);
127 if (!IsValidEnumType (c.Type)) {
128 Report.Error (1008, Location, "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
133 value = new EnumConstant (c, parent_enum.TypeBuilder);
137 if (prev_member == null) {
138 value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
142 if (!prev_member.ResolveValue ())
148 value = prev_member.value.Increment ();
150 catch (OverflowException) {
151 Report.Error (543, Location, "The enumerator value `{0}' is too large to fit in its type `{1}'",
152 GetSignatureForError (), TypeManager.CSharpName (parent_enum.UnderlyingType));
160 public bool Emit (EmitContext ec)
162 if (OptAttributes != null)
163 OptAttributes.Emit (ec, this);
165 if (!ResolveValue ())
168 builder.SetConstant (value.GetValue ());
173 public override string GetSignatureForError()
175 return String.Concat (parent_enum.GetSignatureForError (), '.', Name);
178 public override string[] ValidAttributeTargets {
180 return attribute_targets;
184 protected override bool VerifyClsCompliance(DeclSpace ds)
186 // Because parent is TypeContainer and we have only DeclSpace parent.
187 // Parameter replacing is required
188 return base.VerifyClsCompliance (parent_enum);
191 public override string DocCommentHeader {
195 #region IConstant Members
197 public Constant Value {
207 /// Enumeration container
209 public class Enum : DeclSpace {
211 public Type UnderlyingType;
213 static MemberList no_list = new MemberList (new object[0]);
215 public const int AllowedModifiers =
218 Modifiers.PROTECTED |
222 public Enum (NamespaceEntry ns, TypeContainer parent, Expression type,
223 int mod_flags, MemberName name, Attributes attrs)
224 : base (ns, parent, name, attrs)
226 this.BaseType = type;
227 ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
228 IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, name.Location);
231 public void AddEnumMember (EnumMember em)
233 if (em.Name == "value__") {
234 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `value__'");
238 if (!AddToContainer (em, em.Name))
242 public override TypeBuilder DefineType ()
244 if (TypeBuilder != null)
247 ec = new EmitContext (this, this, Location, null, null, ModFlags, false);
248 ec.InEnumContext = true;
250 if (!(BaseType is TypeLookupExpression)) {
251 Report.Error (1008, Location,
252 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
256 TypeExpr ute = ResolveBaseTypeExpr (BaseType, false, Location);
260 UnderlyingType = ute.Type;
262 if (UnderlyingType != TypeManager.int32_type &&
263 UnderlyingType != TypeManager.uint32_type &&
264 UnderlyingType != TypeManager.int64_type &&
265 UnderlyingType != TypeManager.uint64_type &&
266 UnderlyingType != TypeManager.short_type &&
267 UnderlyingType != TypeManager.ushort_type &&
268 UnderlyingType != TypeManager.byte_type &&
269 UnderlyingType != TypeManager.sbyte_type) {
270 Report.Error (1008, Location,
271 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
276 if (TypeManager.NamespaceClash (Name, Location))
279 ModuleBuilder builder = CodeGen.Module.Builder;
281 TypeBuilder = builder.DefineType (Name, TypeAttr, TypeManager.enum_type);
283 TypeBuilder builder = Parent.TypeBuilder;
285 TypeBuilder = builder.DefineNestedType (
286 Basename, TypeAttr, TypeManager.enum_type);
289 ec.ContainerType = TypeBuilder;
292 // Call MapToInternalType for corlib
294 TypeBuilder.DefineField ("value__", UnderlyingType,
295 FieldAttributes.Public | FieldAttributes.SpecialName
296 | FieldAttributes.RTSpecialName);
298 TypeManager.AddUserType (Name, this);
300 foreach (EnumMember em in defined_names.Values) {
308 public override bool Define ()
313 public override void Emit ()
315 if (OptAttributes != null) {
316 OptAttributes.Emit (ec, this);
319 foreach (EnumMember em in defined_names.Values) {
330 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
331 MemberFilter filter, object criteria)
333 if ((mt & MemberTypes.Field) == 0)
336 EnumMember em = defined_names [criteria] as EnumMember;
340 FieldBuilder[] fb = new FieldBuilder[] { em.builder };
341 return new MemberList (fb);
344 void VerifyClsName ()
346 HybridDictionary dict = new HybridDictionary (defined_names.Count, true);
347 foreach (EnumMember em in defined_names.Values) {
348 if (!em.IsClsComplianceRequired (this))
352 dict.Add (em.Name, em);
354 catch (ArgumentException) {
355 Report.SymbolRelatedToPreviousError ((MemberCore)dict [em.Name]);
356 Report.Warning (3005, em.Location, "Identifier `{0}' differing only in case is not CLS-compliant", em.GetSignatureForError ());
361 protected override bool VerifyClsCompliance (DeclSpace ds)
363 if (!base.VerifyClsCompliance (ds))
368 if (!AttributeTester.IsClsCompliant (UnderlyingType)) {
369 Report.Error (3009, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
376 public override MemberCache MemberCache {
382 public override AttributeTargets AttributeTargets {
384 return AttributeTargets.Enum;
388 protected override TypeAttributes TypeAttr {
390 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
391 TypeAttributes.Class | TypeAttributes.Sealed |
397 // Generates xml doc comments (if any), and if required,
398 // handle warning report.
400 internal override void GenerateDocComment (DeclSpace ds)
402 base.GenerateDocComment (ds);
404 foreach (EnumMember em in defined_names.Values) {
405 em.GenerateDocComment (this);
410 // Represents header string for documentation comment.
412 public override string DocCommentHeader {