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;
20 namespace Mono.CSharp {
22 public class EnumMember : MemberCore, IConstant {
23 static string[] attribute_targets = new string [] { "field" };
25 public FieldBuilder builder;
27 readonly Enum parent_enum;
28 readonly Expression ValueExpr;
29 readonly EnumMember prev_member;
34 // TODO: remove or simplify
37 public EnumMember (Enum parent_enum, EnumMember prev_member, Expression expr,
38 MemberName name, Attributes attrs):
39 base (parent_enum, name, attrs)
41 this.parent_enum = parent_enum;
42 this.ModFlags = parent_enum.ModFlags;
43 this.ValueExpr = expr;
44 this.prev_member = prev_member;
46 ec = new EmitContext (this, parent_enum, parent_enum, Location, null, null, ModFlags, false);
47 ec.InEnumContext = true;
50 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
52 if (a.Type == TypeManager.marshal_as_attr_type) {
53 UnmanagedMarshal marshal = a.GetMarshal (this);
54 if (marshal != null) {
55 builder.SetMarshal (marshal);
60 if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
61 a.Error_InvalidSecurityParent ();
65 builder.SetCustomAttribute (cb);
68 public override AttributeTargets AttributeTargets {
70 return AttributeTargets.Field;
74 static bool IsValidEnumType (Type t)
76 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
77 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
78 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
82 public override bool Define ()
84 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
85 TypeBuilder tb = parent_enum.TypeBuilder;
86 builder = tb.DefineField (Name, tb, attr);
87 ec.ContainerType = tb;
89 TypeManager.RegisterConstant (builder, this);
93 // Because parent is TypeContainer and we have DeclSpace only
94 public override void CheckObsoleteness (Location loc)
96 parent_enum.CheckObsoleteness (loc);
98 ObsoleteAttribute oa = GetObsoleteAttribute ();
103 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
106 public bool ResolveValue ()
112 Const.Error_CyclicDeclaration (this);
116 if (ValueExpr != null) {
118 Constant c = ValueExpr.ResolveAsConstant (ec, this);
124 if (c is EnumConstant)
125 c = ((EnumConstant)c).Child;
127 c = c.ImplicitConversionRequired (parent_enum.UnderlyingType, Location);
131 if (!IsValidEnumType (c.Type)) {
132 Report.Error (1008, Location, "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
137 value = new EnumConstant (c, parent_enum.TypeBuilder);
141 if (prev_member == null) {
142 value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
146 if (!prev_member.ResolveValue ()) {
147 // Suppress cyclic error
148 prev_member.value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
155 value = (EnumConstant)prev_member.value.Increment ();
157 catch (OverflowException) {
158 Report.Error (543, Location, "The enumerator value `{0}' is too large to fit in its type `{1}'",
159 GetSignatureForError (), TypeManager.CSharpName (parent_enum.UnderlyingType));
167 public override void Emit ()
169 if (OptAttributes != null)
170 OptAttributes.Emit ();
172 if (!ResolveValue ()) {
173 // Suppress cyclic errors
174 value = new EnumConstant(New.Constantify(parent_enum.UnderlyingType), parent_enum.TypeBuilder);
178 builder.SetConstant (value.GetValue ());
182 public override string GetSignatureForError()
184 return String.Concat (parent_enum.GetSignatureForError (), '.', Name);
187 public override string[] ValidAttributeTargets {
189 return attribute_targets;
193 public override string DocCommentHeader {
197 public object Value { get { return value.GetValue (); } }
199 #region IConstant Members
201 public Constant CreateConstantReference (Location loc)
206 return new EnumConstant (Constant.CreateConstant (value.Child.Type, value.Child.GetValue(), loc),
214 /// Enumeration container
216 public class Enum : DeclSpace {
218 public Type UnderlyingType;
220 static MemberList no_list = new MemberList (new object[0]);
222 public const int AllowedModifiers =
225 Modifiers.PROTECTED |
229 public Enum (NamespaceEntry ns, DeclSpace parent, Expression type,
230 int mod_flags, MemberName name, Attributes attrs)
231 : base (ns, parent, name, attrs)
233 this.BaseType = type;
234 ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
235 IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, name.Location);
238 public void AddEnumMember (EnumMember em)
240 if (em.Name == "value__") {
241 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `value__'");
245 if (!AddToContainer (em, em.Name))
249 public override TypeBuilder DefineType ()
251 if (TypeBuilder != null)
254 if (!(BaseType is TypeLookupExpression)) {
255 Report.Error (1008, Location,
256 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
260 TypeExpr ute = BaseType.ResolveAsTypeTerminal (this, false);
261 UnderlyingType = ute.Type;
263 if (UnderlyingType != TypeManager.int32_type &&
264 UnderlyingType != TypeManager.uint32_type &&
265 UnderlyingType != TypeManager.int64_type &&
266 UnderlyingType != TypeManager.uint64_type &&
267 UnderlyingType != TypeManager.short_type &&
268 UnderlyingType != TypeManager.ushort_type &&
269 UnderlyingType != TypeManager.byte_type &&
270 UnderlyingType != TypeManager.sbyte_type) {
271 Report.Error (1008, Location,
272 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
277 if (TypeManager.NamespaceClash (Name, Location))
280 ModuleBuilder builder = CodeGen.Module.Builder;
282 TypeBuilder = builder.DefineType (Name, TypeAttr, TypeManager.enum_type);
284 TypeBuilder builder = Parent.TypeBuilder;
286 TypeBuilder = builder.DefineNestedType (
287 Basename, TypeAttr, TypeManager.enum_type);
291 // Call MapToInternalType for corlib
293 TypeBuilder.DefineField ("value__", UnderlyingType,
294 FieldAttributes.Public | FieldAttributes.SpecialName
295 | FieldAttributes.RTSpecialName);
297 TypeManager.AddUserType (this);
299 foreach (EnumMember em in defined_names.Values) {
307 public override bool Define ()
312 public override void Emit ()
314 if (OptAttributes != null) {
315 OptAttributes.Emit ();
318 foreach (EnumMember em in defined_names.Values) {
328 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
329 MemberFilter filter, object criteria)
331 if ((mt & MemberTypes.Field) == 0)
334 EnumMember em = defined_names [criteria] as EnumMember;
338 FieldBuilder[] fb = new FieldBuilder[] { em.builder };
339 return new MemberList (fb);
343 // Used for error reporting only
345 public EnumMember GetDefinition (object value)
347 foreach (EnumMember e in defined_names.Values) {
348 if (e.Value.Equals (value))
352 throw new ArgumentOutOfRangeException (value.ToString ());
356 void VerifyClsName ()
358 HybridDictionary dict = new HybridDictionary (defined_names.Count, true);
359 foreach (EnumMember em in defined_names.Values) {
360 if (!em.IsClsComplianceRequired ())
364 dict.Add (em.Name, em);
366 catch (ArgumentException) {
367 Report.SymbolRelatedToPreviousError (em);
368 MemberCore col = (MemberCore)dict [em.Name];
370 Report.Warning (3005, 1, col.Location, "Identifier `{0}' differing only in case is not CLS-compliant", col.GetSignatureForError ());
372 Report.Error (3005, col.Location, "Identifier `{0}' differing only in case is not CLS-compliant", col.GetSignatureForError ());
378 protected override bool VerifyClsCompliance ()
380 if (!base.VerifyClsCompliance ())
385 if (UnderlyingType == TypeManager.uint32_type ||
386 UnderlyingType == TypeManager.uint64_type ||
387 UnderlyingType == TypeManager.ushort_type) {
388 Report.Error (3009, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
395 public override MemberCache MemberCache {
401 public override AttributeTargets AttributeTargets {
403 return AttributeTargets.Enum;
407 protected override TypeAttributes TypeAttr {
409 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
410 TypeAttributes.Class | TypeAttributes.Sealed |
416 // Generates xml doc comments (if any), and if required,
417 // handle warning report.
419 internal override void GenerateDocComment (DeclSpace ds)
421 base.GenerateDocComment (ds);
423 foreach (EnumMember em in defined_names.Values) {
424 em.GenerateDocComment (this);
429 // Represents header string for documentation comment.
431 public override string DocCommentHeader {