fixed tests
[mono.git] / mcs / mcs / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //         Marek Safar     (marek.safar@seznam.cz)
7 //
8 // Licensed under the terms of the GNU GPL
9 //
10 // (C) 2001 Ximian, Inc (http://www.ximian.com)
11 //
12
13 using System;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Globalization;
19
20 namespace Mono.CSharp {
21
22         public class EnumMember : MemberCore, IConstant {
23                 static string[] attribute_targets = new string [] { "field" };
24
25                 public FieldBuilder builder;
26
27                 readonly Enum parent_enum;
28                 readonly Expression ValueExpr;
29                 readonly EnumMember prev_member;
30
31                 EnumConstant value;
32                 bool in_transit;
33
34                 // TODO: remove or simplify
35                 EmitContext ec;
36
37                 public EnumMember (Enum parent_enum, EnumMember prev_member, Expression expr,
38                                 MemberName name, Attributes attrs):
39                         base (parent_enum, name, attrs)
40                 {
41                         this.parent_enum = parent_enum;
42                         this.ModFlags = parent_enum.ModFlags;
43                         this.ValueExpr = expr;
44                         this.prev_member = prev_member;
45
46                         ec = new EmitContext (this, parent_enum, parent_enum, Location, null, null, ModFlags, false);
47                         ec.InEnumContext = true;
48                 }
49
50                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
51                 {
52                         if (a.Type == TypeManager.marshal_as_attr_type) {
53                                 UnmanagedMarshal marshal = a.GetMarshal (this);
54                                 if (marshal != null) {
55                                         builder.SetMarshal (marshal);
56                                 }
57                                 return;
58                         }
59
60                         if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
61                                 a.Error_InvalidSecurityParent ();
62                                 return;
63                         }
64
65                         builder.SetCustomAttribute (cb);
66                 }
67
68                 public override AttributeTargets AttributeTargets {
69                         get {
70                                 return AttributeTargets.Field;
71                         }
72                 }
73
74                 static bool IsValidEnumType (Type t)
75                 {
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 ||
79                                 t.IsEnum);
80                 }
81         
82                 public override bool Define ()
83                 {
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;
88
89                         TypeManager.RegisterConstant (builder, this);
90                         return true;
91                 }
92
93                 // Because parent is TypeContainer and we have DeclSpace only
94                 public override void CheckObsoleteness (Location loc)
95                 {
96                         parent_enum.CheckObsoleteness (loc);
97
98                         ObsoleteAttribute oa = GetObsoleteAttribute ();
99                         if (oa == null) {
100                                 return;
101                         }
102
103                         AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
104                 }
105
106                 public bool ResolveValue ()
107                 {
108                         if (value != null)
109                                 return true;
110
111                         if (in_transit) {
112                                 Const.Error_CyclicDeclaration (this);
113                                 return false;
114                         }
115
116                         if (ValueExpr != null) {
117                                 in_transit = true;
118                                 Constant c = ValueExpr.ResolveAsConstant (ec, this);
119                                 in_transit = false;
120
121                                 if (c == null)
122                                         return false;
123
124                                 if (c is EnumConstant)
125                                         c = ((EnumConstant)c).Child;
126                                         
127                                 c = c.ImplicitConversionRequired (parent_enum.UnderlyingType, Location);
128                                 if (c == null)
129                                         return false;
130
131                                 if (!IsValidEnumType (c.Type)) {
132                                         Report.Error (1008, Location, "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
133                                         return false;
134                                 }
135
136                                 in_transit = false;
137                                 value = new EnumConstant (c, parent_enum.TypeBuilder);
138                                 return true;
139                         }
140
141                         if (prev_member == null) {
142                                 value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
143                                 return true;
144                         }
145
146                         if (!prev_member.ResolveValue ()) {
147                                 // Suppress cyclic error
148                                 prev_member.value = new EnumConstant (New.Constantify (parent_enum.UnderlyingType), parent_enum.TypeBuilder);
149                                 return false;
150                         }
151
152                         in_transit = true;
153
154                         try {
155                                 value = (EnumConstant)prev_member.value.Increment ();
156                         }
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));
160                                 return false;
161                         }
162                         in_transit = false;
163
164                         return true;
165                 }
166
167                 public override void Emit ()
168                 {
169                         if (OptAttributes != null)
170                                 OptAttributes.Emit (); 
171
172                         if (!ResolveValue ()) {
173                                 // Suppress cyclic errors
174                                 value = new EnumConstant(New.Constantify(parent_enum.UnderlyingType), parent_enum.TypeBuilder);
175                                 return;
176                         }
177
178                         builder.SetConstant (value.GetValue ());
179                         base.Emit ();
180                 }
181
182                 public override string GetSignatureForError()
183                 {
184                         return String.Concat (parent_enum.GetSignatureForError (), '.', Name);
185                 }
186
187                 public override string[] ValidAttributeTargets {
188                         get {
189                                 return attribute_targets;
190                         }
191                 }
192
193                 public override string DocCommentHeader {
194                         get { return "F:"; }
195                 }
196
197                 public object Value { get { return value.GetValue (); } }
198
199                 #region IConstant Members
200
201                 public Constant CreateConstantReference (Location loc)
202                 {
203                         if (value == null)
204                                 return null;
205
206                         return new EnumConstant (Constant.CreateConstant (value.Child.Type, value.Child.GetValue(), loc),
207                                 value.Type);
208                 }
209
210                 #endregion
211         }
212
213         /// <summary>
214         ///   Enumeration container
215         /// </summary>
216         public class Enum : DeclSpace {
217                 Expression BaseType;
218                 public Type UnderlyingType;
219
220                 static MemberList no_list = new MemberList (new object[0]);
221                 
222                 public const int AllowedModifiers =
223                         Modifiers.NEW |
224                         Modifiers.PUBLIC |
225                         Modifiers.PROTECTED |
226                         Modifiers.INTERNAL |
227                         Modifiers.PRIVATE;
228
229                 public Enum (NamespaceEntry ns, DeclSpace parent, Expression type,
230                              int mod_flags, MemberName name, Attributes attrs)
231                         : base (ns, parent, name, attrs)
232                 {
233                         this.BaseType = type;
234                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
235                                                     IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, name.Location);
236                 }
237
238                 public void AddEnumMember (EnumMember em)
239                 {
240                         if (em.Name == "value__") {
241                                 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `value__'");
242                                 return;
243                         }
244
245                         if (!AddToContainer (em, em.Name))
246                                 return;
247                 }
248                 
249                 public override TypeBuilder DefineType ()
250                 {
251                         if (TypeBuilder != null)
252                                 return TypeBuilder;
253
254                         if (!(BaseType is TypeLookupExpression)) {
255                                 Report.Error (1008, Location,
256                                         "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
257                                 return null;
258                         }
259
260                         TypeExpr ute = BaseType.ResolveAsTypeTerminal (this, false);
261                         UnderlyingType = ute.Type;
262
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");
273                                 return null;
274                         }
275
276                         if (IsTopLevel) {
277                                 if (TypeManager.NamespaceClash (Name, Location))
278                                         return null;
279                                 
280                                 ModuleBuilder builder = CodeGen.Module.Builder;
281
282                                 TypeBuilder = builder.DefineType (Name, TypeAttr, TypeManager.enum_type);
283                         } else {
284                                 TypeBuilder builder = Parent.TypeBuilder;
285
286                                 TypeBuilder = builder.DefineNestedType (
287                                         Basename, TypeAttr, TypeManager.enum_type);
288                         }
289
290                         //
291                         // Call MapToInternalType for corlib
292                         //
293                         TypeBuilder.DefineField ("value__", UnderlyingType,
294                                                  FieldAttributes.Public | FieldAttributes.SpecialName
295                                                  | FieldAttributes.RTSpecialName);
296
297                         TypeManager.AddUserType (this);
298
299                         foreach (EnumMember em in defined_names.Values) {
300                                 if (!em.Define ())
301                                         return null;
302                         }
303
304                         return TypeBuilder;
305                 }
306                 
307                 public override bool Define ()
308                 {
309                         return true;
310                 }
311
312                 public override void Emit ()
313                 {
314                         if (OptAttributes != null) {
315                                 OptAttributes.Emit ();
316                         }
317
318                         foreach (EnumMember em in defined_names.Values) {
319                                 em.Emit ();
320                         }
321
322                         base.Emit ();
323                 }
324
325                 //
326                 // IMemberFinder
327                 //
328                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
329                         MemberFilter filter, object criteria)
330                 {
331                         if ((mt & MemberTypes.Field) == 0)
332                                 return no_list;
333
334                         EnumMember em = defined_names [criteria] as EnumMember;
335                         if (em == null)
336                                 return no_list;
337
338                         FieldBuilder[] fb = new FieldBuilder[] { em.builder };
339                         return new MemberList (fb);
340                 }
341
342                 //
343                 // Used for error reporting only
344                 //
345                 public EnumMember GetDefinition (object value)
346                 {
347                         foreach (EnumMember e in defined_names.Values) {
348                                 if (e.Value.Equals (value))
349                                         return e;
350                         }
351
352                         throw new ArgumentOutOfRangeException (value.ToString ());
353                 }
354
355                 
356                 void VerifyClsName ()
357                 {
358                         HybridDictionary dict = new HybridDictionary (defined_names.Count, true);
359                         foreach (EnumMember em in defined_names.Values) {
360                                 if (!em.IsClsComplianceRequired ())
361                                         continue;
362
363                                 try {
364                                         dict.Add (em.Name, em);
365                                 }
366                                 catch (ArgumentException) {
367                                         Report.SymbolRelatedToPreviousError (em);
368                                         MemberCore col = (MemberCore)dict [em.Name];
369 #if GMCS_SOURCE
370                                         Report.Warning (3005, 1, col.Location, "Identifier `{0}' differing only in case is not CLS-compliant", col.GetSignatureForError ());
371 #else
372                                         Report.Error (3005, col.Location, "Identifier `{0}' differing only in case is not CLS-compliant", col.GetSignatureForError ());
373 #endif
374                                 }
375                         }
376                 }
377
378                 protected override bool VerifyClsCompliance ()
379                 {
380                         if (!base.VerifyClsCompliance ())
381                                 return false;
382
383                         VerifyClsName ();
384
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));
389                         }
390
391                         return true;
392                 }
393         
394
395                 public override MemberCache MemberCache {
396                         get {
397                                 return null;
398                         }
399                 }
400
401                 public override AttributeTargets AttributeTargets {
402                         get {
403                                 return AttributeTargets.Enum;
404                         }
405                 }
406
407                 protected override TypeAttributes TypeAttr {
408                         get {
409                                 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
410                                 TypeAttributes.Class | TypeAttributes.Sealed |
411                                 base.TypeAttr;
412                         }
413                 }
414
415                 //
416                 // Generates xml doc comments (if any), and if required,
417                 // handle warning report.
418                 //
419                 internal override void GenerateDocComment (DeclSpace ds)
420                 {
421                         base.GenerateDocComment (ds);
422
423                         foreach (EnumMember em in defined_names.Values) {
424                                 em.GenerateDocComment (this);
425                         }
426                 }
427
428                 //
429                 //   Represents header string for documentation comment.
430                 //
431                 public override string DocCommentHeader {
432                         get { return "T:"; }
433                 }
434         }
435 }