2004-09-01 Marek Safar <marek.safar@seznam.cz>
[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 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Globalization;
17
18 namespace Mono.CSharp {
19
20         class EnumMember: MemberCore {
21                 static string[] attribute_targets = new string [] { "field" };
22
23                 Enum parent_enum;
24                 public FieldBuilder builder;
25
26                 public EnumMember (Enum parent_enum, string name, Location loc, Attributes attrs):
27                         base (null, name, attrs, loc)
28                 {
29                         this.parent_enum = parent_enum;
30                 }
31
32                 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
33                 {
34                         if (a.Type == TypeManager.marshal_as_attr_type) {
35                                 UnmanagedMarshal marshal = a.GetMarshal ();
36                                 if (marshal != null) {
37                                         builder.SetMarshal (marshal);
38                                         return;
39                                 }
40                                 Report.Warning (-24, a.Location, "The Microsoft Runtime cannot set this marshal info. Please use the Mono runtime instead.");
41                                 return;
42                         }
43
44                         builder.SetCustomAttribute (cb);
45                 }
46
47                 public override AttributeTargets AttributeTargets {
48                         get {
49                                 return AttributeTargets.Field;
50                         }
51                 }
52
53                 public override bool IsClsCompliaceRequired (DeclSpace ds)
54                 {
55                         return parent_enum.IsClsCompliaceRequired (ds);
56                 }
57
58                 public void DefineMember (TypeBuilder tb)
59                 {
60                         FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
61                                 | FieldAttributes.Literal;
62                         
63                         builder = tb.DefineField (Name, tb, attr);
64                 }
65
66                 public override bool Define ()
67                 {
68                         throw new NotImplementedException ();
69                 }
70
71                 public void Emit (EmitContext ec)
72                 {
73                         if (OptAttributes != null)
74                                 OptAttributes.Emit (ec, this); 
75                 }
76
77                 // TODO: caching would be usefull
78                 public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec)
79                 {
80                         if (OptAttributes == null)
81                                 return null;
82
83                         Attribute obsolete_attr = OptAttributes.Search (TypeManager.obsolete_attribute_type, ec);
84                         if (obsolete_attr == null)
85                                 return null;
86
87                         ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ec.DeclSpace);
88                         if (obsolete == null)
89                                 return null;
90
91                         return obsolete;
92                 }
93
94                 public override string[] ValidAttributeTargets {
95                         get {
96                                 return attribute_targets;
97                         }
98                 }
99
100                 protected override void VerifyObsoleteAttribute()
101                 {
102                         throw new NotImplementedException ();
103                 }
104
105         }
106
107         /// <summary>
108         ///   Enumeration container
109         /// </summary>
110         public class Enum : DeclSpace {
111                 ArrayList ordered_enums;
112                 
113                 public Expression BaseType;
114                 
115                 public Type UnderlyingType;
116
117                 Hashtable member_to_location;
118                 Hashtable member_to_attributes;
119
120                 //
121                 // This is for members that have been defined
122                 //
123                 Hashtable member_to_value;
124
125                 //
126                 // This is used to mark members we're currently defining
127                 //
128                 Hashtable in_transit;
129                 
130                 ArrayList field_builders;
131
132
133                 Hashtable name_to_member;
134                 
135                 public const int AllowedModifiers =
136                         Modifiers.NEW |
137                         Modifiers.PUBLIC |
138                         Modifiers.PROTECTED |
139                         Modifiers.INTERNAL |
140                         Modifiers.PRIVATE;
141
142                 public Enum (NamespaceEntry ns, TypeContainer parent, Expression type, int mod_flags,
143                              string name, Attributes attrs, Location l)
144                         : base (ns, parent, name, attrs, l)
145                 {
146                         this.BaseType = type;
147                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
148                                                     IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l);
149
150                         ordered_enums = new ArrayList ();
151                         member_to_location = new Hashtable ();
152                         member_to_value = new Hashtable ();
153                         in_transit = new Hashtable ();
154                         field_builders = new ArrayList ();
155
156                         name_to_member = new Hashtable ();
157                 }
158
159                 /// <summary>
160                 ///   Adds @name to the enumeration space, with @expr
161                 ///   being its definition.  
162                 /// </summary>
163                 public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
164                                                      Attributes opt_attrs)
165                 {
166                         if (defined_names.Contains (name))
167                                 return AdditionResult.NameExists;
168
169                         if (name == "value__") {
170                                 Report.Error (76, loc, "An item in an enumeration can't have an identifier `value__'");
171                                 return AdditionResult.Error;
172                         }
173
174                         DefineName (name, expr);
175
176                         ordered_enums.Add (name);
177                         member_to_location.Add (name, loc);
178
179                         if (member_to_attributes == null)
180                                 member_to_attributes = new Hashtable ();
181
182                         member_to_attributes.Add (name, opt_attrs);
183
184                         name_to_member.Add (name, new EnumMember (this, name, loc, opt_attrs));
185                         
186                         return AdditionResult.Success;
187                 }
188
189                 //
190                 // This is used by corlib compilation: we map from our
191                 // type to a type that is consumable by the DefineField
192                 //
193                 Type MapToInternalType (Type t)
194                 {
195                         if (t == TypeManager.int32_type)
196                                 return typeof (int);
197                         if (t == TypeManager.int64_type)
198                                 return typeof (long);
199                         if (t == TypeManager.uint32_type)
200                                 return typeof (uint);
201                         if (t == TypeManager.uint64_type)
202                                 return typeof (ulong);
203                         if (t == TypeManager.float_type)
204                                 return typeof (float);
205                         if (t == TypeManager.double_type)
206                                 return typeof (double);
207                         if (t == TypeManager.byte_type)
208                                 return typeof (byte);
209                         if (t == TypeManager.sbyte_type)
210                                 return typeof (sbyte);
211                         if (t == TypeManager.char_type)
212                                 return typeof (char);
213                         if (t == TypeManager.short_type)
214                                 return typeof (short);
215                         if (t == TypeManager.ushort_type)
216                                 return typeof (ushort);
217
218                         throw new Exception ();
219                 }
220                 
221                 public override TypeBuilder DefineType ()
222                 {
223                         if (TypeBuilder != null)
224                                 return TypeBuilder;
225
226                         TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
227
228                         attr |= TypeAttributes.Class | TypeAttributes.Sealed;
229
230                         if (!(BaseType is TypeLookupExpression)) {
231                                 Report.Error (1008, Location,
232                                               "Type byte, sbyte, short, ushort, int, uint, " +
233                                               "long, or ulong expected (got: `{0}')", BaseType);
234                                 return null;
235                         }
236
237                         UnderlyingType = ResolveType (BaseType, false, Location);
238
239                         if (UnderlyingType != TypeManager.int32_type &&
240                             UnderlyingType != TypeManager.uint32_type &&
241                             UnderlyingType != TypeManager.int64_type &&
242                             UnderlyingType != TypeManager.uint64_type &&
243                             UnderlyingType != TypeManager.short_type &&
244                             UnderlyingType != TypeManager.ushort_type &&
245                             UnderlyingType != TypeManager.byte_type  &&
246                             UnderlyingType != TypeManager.sbyte_type) {
247                                 Report.Error (1008, Location,
248                                               "Type byte, sbyte, short, ushort, int, uint, " +
249                                               "long, or ulong expected (got: " +
250                                               TypeManager.CSharpName (UnderlyingType) + ")");
251                                 return null;
252                         }
253
254                         if (IsTopLevel) {
255                                 if (TypeManager.NamespaceClash (Name, Location))
256                                         return null;
257                                 
258                                 ModuleBuilder builder = CodeGen.Module.Builder;
259
260                                 TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
261                         } else {
262                                 TypeBuilder builder = Parent.TypeBuilder;
263
264                                 TypeBuilder = builder.DefineNestedType (
265                                         Basename, attr, TypeManager.enum_type);
266                         }
267
268                         //
269                         // Call MapToInternalType for corlib
270                         //
271                         TypeBuilder.DefineField ("value__", UnderlyingType,
272                                                  FieldAttributes.Public | FieldAttributes.SpecialName
273                                                  | FieldAttributes.RTSpecialName);
274
275                         TypeManager.AddEnumType (Name, TypeBuilder, this);
276
277                         return TypeBuilder;
278                 }
279
280                 bool IsValidEnumConstant (Expression e)
281                 {
282                         if (!(e is Constant))
283                                 return false;
284
285                         if (e is IntConstant || e is UIntConstant || e is LongConstant ||
286                             e is ByteConstant || e is SByteConstant || e is ShortConstant ||
287                             e is UShortConstant || e is ULongConstant || e is EnumConstant ||
288                             e is CharConstant)
289                                 return true;
290                         else
291                                 return false;
292                 }
293
294                 object GetNextDefaultValue (object default_value)
295                 {
296                         if (UnderlyingType == TypeManager.int32_type) {
297                                 int i = (int) default_value;
298                                 
299                                 if (i < System.Int32.MaxValue)
300                                         return ++i;
301                                 else
302                                         return null;
303                         } else if (UnderlyingType == TypeManager.uint32_type) {
304                                 uint i = (uint) default_value;
305
306                                 if (i < System.UInt32.MaxValue)
307                                         return ++i;
308                                 else
309                                         return null;
310                         } else if (UnderlyingType == TypeManager.int64_type) {
311                                 long i = (long) default_value;
312
313                                 if (i < System.Int64.MaxValue)
314                                         return ++i;
315                                 else
316                                         return null;
317                         } else if (UnderlyingType == TypeManager.uint64_type) {
318                                 ulong i = (ulong) default_value;
319
320                                 if (i < System.UInt64.MaxValue)
321                                         return ++i;
322                                 else
323                                         return null;
324                         } else if (UnderlyingType == TypeManager.short_type) {
325                                 short i = (short) default_value;
326
327                                 if (i < System.Int16.MaxValue)
328                                         return ++i;
329                                 else
330                                         return null;
331                         } else if (UnderlyingType == TypeManager.ushort_type) {
332                                 ushort i = (ushort) default_value;
333
334                                 if (i < System.UInt16.MaxValue)
335                                         return ++i;
336                                 else
337                                         return null;
338                         } else if (UnderlyingType == TypeManager.byte_type) {
339                                 byte i = (byte) default_value;
340
341                                 if (i < System.Byte.MaxValue)
342                                         return ++i;
343                                 else
344                                         return null;
345                         } else if (UnderlyingType == TypeManager.sbyte_type) {
346                                 sbyte i = (sbyte) default_value;
347
348                                 if (i < System.SByte.MaxValue)
349                                         return ++i;
350                                 else
351                                         return null;
352                         }
353
354                         return null;
355                 }
356
357                 void Error_ConstantValueCannotBeConverted (object val, Location loc)
358                 {
359                         if (val is Constant)
360                                 Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () +
361                                               "' cannot be converted" +
362                                               " to a " + TypeManager.CSharpName (UnderlyingType));
363                         else 
364                                 Report.Error (31, loc, "Constant value '" + val +
365                                               "' cannot be converted" +
366                                               " to a " + TypeManager.CSharpName (UnderlyingType));
367                         return;
368                 }
369
370                 /// <summary>
371                 ///  Determines if a standard implicit conversion exists from
372                 ///  expr_type to target_type
373                 /// </summary>
374                 public static bool ImplicitConversionExists (Type expr_type, Type target_type)
375                 {
376                         expr_type = TypeManager.TypeToCoreType (expr_type);
377
378                         if (expr_type == TypeManager.void_type)
379                                 return false;
380                         
381                         if (expr_type == target_type)
382                                 return true;
383
384                         // First numeric conversions 
385
386                         if (expr_type == TypeManager.sbyte_type){
387                                 //
388                                 // From sbyte to short, int, long, float, double.
389                                 //
390                                 if ((target_type == TypeManager.int32_type) || 
391                                     (target_type == TypeManager.int64_type) ||
392                                     (target_type == TypeManager.double_type) ||
393                                     (target_type == TypeManager.float_type)  ||
394                                     (target_type == TypeManager.short_type) ||
395                                     (target_type == TypeManager.decimal_type))
396                                         return true;
397                                 
398                         } else if (expr_type == TypeManager.byte_type){
399                                 //
400                                 // From byte to short, ushort, int, uint, long, ulong, float, double
401                                 // 
402                                 if ((target_type == TypeManager.short_type) ||
403                                     (target_type == TypeManager.ushort_type) ||
404                                     (target_type == TypeManager.int32_type) ||
405                                     (target_type == TypeManager.uint32_type) ||
406                                     (target_type == TypeManager.uint64_type) ||
407                                     (target_type == TypeManager.int64_type) ||
408                                     (target_type == TypeManager.float_type) ||
409                                     (target_type == TypeManager.double_type) ||
410                                     (target_type == TypeManager.decimal_type))
411                                         return true;
412         
413                         } else if (expr_type == TypeManager.short_type){
414                                 //
415                                 // From short to int, long, float, double
416                                 // 
417                                 if ((target_type == TypeManager.int32_type) ||
418                                     (target_type == TypeManager.int64_type) ||
419                                     (target_type == TypeManager.double_type) ||
420                                     (target_type == TypeManager.float_type) ||
421                                     (target_type == TypeManager.decimal_type))
422                                         return true;
423                                         
424                         } else if (expr_type == TypeManager.ushort_type){
425                                 //
426                                 // From ushort to int, uint, long, ulong, float, double
427                                 //
428                                 if ((target_type == TypeManager.uint32_type) ||
429                                     (target_type == TypeManager.uint64_type) ||
430                                     (target_type == TypeManager.int32_type) ||
431                                     (target_type == TypeManager.int64_type) ||
432                                     (target_type == TypeManager.double_type) ||
433                                     (target_type == TypeManager.float_type) ||
434                                     (target_type == TypeManager.decimal_type))
435                                         return true;
436                                     
437                         } else if (expr_type == TypeManager.int32_type){
438                                 //
439                                 // From int to long, float, double
440                                 //
441                                 if ((target_type == TypeManager.int64_type) ||
442                                     (target_type == TypeManager.double_type) ||
443                                     (target_type == TypeManager.float_type) ||
444                                     (target_type == TypeManager.decimal_type))
445                                         return true;
446                                         
447                         } else if (expr_type == TypeManager.uint32_type){
448                                 //
449                                 // From uint to long, ulong, float, double
450                                 //
451                                 if ((target_type == TypeManager.int64_type) ||
452                                     (target_type == TypeManager.uint64_type) ||
453                                     (target_type == TypeManager.double_type) ||
454                                     (target_type == TypeManager.float_type) ||
455                                     (target_type == TypeManager.decimal_type))
456                                         return true;
457                                         
458                         } else if ((expr_type == TypeManager.uint64_type) ||
459                                    (expr_type == TypeManager.int64_type)) {
460                                 //
461                                 // From long/ulong to float, double
462                                 //
463                                 if ((target_type == TypeManager.double_type) ||
464                                     (target_type == TypeManager.float_type) ||
465                                     (target_type == TypeManager.decimal_type))
466                                         return true;
467                                     
468                         } else if (expr_type == TypeManager.char_type){
469                                 //
470                                 // From char to ushort, int, uint, long, ulong, float, double
471                                 // 
472                                 if ((target_type == TypeManager.ushort_type) ||
473                                     (target_type == TypeManager.int32_type) ||
474                                     (target_type == TypeManager.uint32_type) ||
475                                     (target_type == TypeManager.uint64_type) ||
476                                     (target_type == TypeManager.int64_type) ||
477                                     (target_type == TypeManager.float_type) ||
478                                     (target_type == TypeManager.double_type) ||
479                                     (target_type == TypeManager.decimal_type))
480                                         return true;
481
482                         } else if (expr_type == TypeManager.float_type){
483                                 //
484                                 // float to double
485                                 //
486                                 if (target_type == TypeManager.double_type)
487                                         return true;
488                         }       
489                         
490                         return false;
491                 }
492
493                 //
494                 // Horrible, horrible.  But there is no other way we can pass the EmitContext
495                 // to the recursive definition triggered by the evaluation of a forward
496                 // expression
497                 //
498                 static EmitContext current_ec = null;
499                 
500                 /// <summary>
501                 ///  This is used to lookup the value of an enum member. If the member is undefined,
502                 ///  it attempts to define it and return its value
503                 /// </summary>
504                 public object LookupEnumValue (EmitContext ec, string name, Location loc)
505                 {
506                         
507                         object default_value = null;
508                         Constant c = null;
509
510                         default_value = member_to_value [name];
511
512                         if (default_value != null)
513                                 return default_value;
514
515                         //
516                         // This may happen if we're calling a method in System.Enum, for instance
517                         // Enum.IsDefined().
518                         //
519                         if (!defined_names.Contains (name))
520                                 return null;
521
522                         if (in_transit.Contains (name)) {
523                                 Report.Error (110, loc, "The evaluation of the constant value for `" +
524                                               Name + "." + name + "' involves a circular definition.");
525                                 return null;
526                         }
527
528                         //
529                         // So if the above doesn't happen, we have a member that is undefined
530                         // We now proceed to define it 
531                         //
532                         Expression val = this [name];
533
534                         if (val == null) {
535                                 
536                                 int idx = ordered_enums.IndexOf (name);
537
538                                 if (idx == 0)
539                                         default_value = 0;
540                                 else {
541                                         for (int i = 0; i < idx; ++i) {
542                                                 string n = (string) ordered_enums [i];
543                                                 Location m_loc = (Mono.CSharp.Location)
544                                                         member_to_location [n];
545                                                 in_transit.Add (name, true);
546
547                                                 EmitContext old_ec = current_ec;
548                                                 current_ec = ec;
549                         
550                                                 default_value = LookupEnumValue (ec, n, m_loc);
551
552                                                 current_ec = old_ec;
553                                                 
554                                                 in_transit.Remove (name);
555                                                 if (default_value == null)
556                                                         return null;
557                                         }
558                                         
559                                         default_value = GetNextDefaultValue (default_value);
560                                 }
561                                 
562                         } else {
563                                 bool old = ec.InEnumContext;
564                                 ec.InEnumContext = true;
565                                 in_transit.Add (name, true);
566
567                                 EmitContext old_ec = current_ec;
568                                 current_ec = ec;
569                                 val = val.Resolve (ec);
570                                 current_ec = old_ec;
571                                 
572                                 in_transit.Remove (name);
573                                 ec.InEnumContext = old;
574
575                                 if (val == null)
576                                         return null;
577
578                                 if (!IsValidEnumConstant (val)) {
579                                         Report.Error (
580                                                 1008, loc,
581                                                 "Type byte, sbyte, short, ushort, int, uint, long, or " +
582                                                 "ulong expected (have: " + val + ")");
583                                         return null;
584                                 }
585
586                                 c = (Constant) val;
587                                 default_value = c.GetValue ();
588
589                                 if (default_value == null) {
590                                         Error_ConstantValueCannotBeConverted (c, loc);
591                                         return null;
592                                 }
593
594                                 if (val is EnumConstant){
595                                         Type etype = TypeManager.EnumToUnderlying (c.Type);
596                                         
597                                         if (!ImplicitConversionExists (etype, UnderlyingType)){
598                                                 Convert.Error_CannotImplicitConversion (
599                                                         loc, c.Type, UnderlyingType);
600                                                 return null;
601                                         }
602                                 }
603                         }
604
605                         EnumMember em = name_to_member [name] as EnumMember;
606                         em.DefineMember (TypeBuilder);
607
608                         bool fail;
609                         default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
610                         if (fail){
611                                 Error_ConstantValueCannotBeConverted (c, loc);
612                                 return null;
613                         }
614
615                         em.builder.SetConstant (default_value);
616                         field_builders.Add (em.builder);
617                         member_to_value [name] = default_value;
618
619                         if (!TypeManager.RegisterFieldValue (em.builder, default_value))
620                                 return null;
621
622                         return default_value;
623                 }
624
625                 public override bool DefineMembers (TypeContainer parent)
626                 {
627                         return true;
628                 }
629                 
630                 public override bool Define ()
631                 {
632                         //
633                         // If there was an error during DefineEnum, return
634                         //
635                         if (TypeBuilder == null)
636                                 return false;
637
638                         EmitContext ec = new EmitContext (this, this, Location, null,
639                                                           UnderlyingType, ModFlags, false);
640
641                         
642                         object default_value = 0;
643                         
644                 
645                         foreach (string name in ordered_enums) {
646                                 //
647                                 // Have we already been defined, thanks to some cross-referencing ?
648                                 // 
649                                 if (member_to_value.Contains (name))
650                                         continue;
651                                 
652                                 Location loc = (Mono.CSharp.Location) member_to_location [name];
653
654                                 if (this [name] != null) {
655                                         default_value = LookupEnumValue (ec, name, loc);
656
657                                         if (default_value == null)
658                                                 return true;
659                                 } else {
660                                         if (name == "value__"){
661                                                 Report.Error (76, loc, "The name `value__' is reserved for enumerations");
662                                                 return false;
663                                         }
664
665                                         EnumMember em = name_to_member [name] as EnumMember;
666
667                                         em.DefineMember (TypeBuilder);
668                                         FieldBuilder fb = em.builder;
669                                         
670                                         if (default_value == null) {
671                                            Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
672                                                               "fit in its type");
673                                                 return false;
674                                         }
675
676                                         bool fail;
677                                         default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
678                                         if (fail){
679                                                 Error_ConstantValueCannotBeConverted (default_value, loc);
680                                                 return false;
681                                         }
682
683                                         fb.SetConstant (default_value);
684                                         field_builders.Add (fb);
685                                         member_to_value [name] = default_value;
686                                         
687                                         if (!TypeManager.RegisterFieldValue (fb, default_value))
688                                                 return false;
689                                 }
690
691                                 default_value = GetNextDefaultValue (default_value);
692                         }
693
694                         return true;
695                 }
696
697                 public override void Emit ()
698                 {
699                         EmitContext ec = new EmitContext (
700                                 Parent, this, Location, null, null, ModFlags, false);
701
702                         if (OptAttributes != null) {
703                                 OptAttributes.Emit (ec, this);
704                         }
705
706                         foreach (EnumMember em in name_to_member.Values) {
707                                 em.Emit (ec);
708                         }
709
710                         base.Emit ();
711                 }
712                 
713                 void VerifyClsName ()
714                 {
715                         Hashtable ht = new Hashtable ();
716                         foreach (string name in ordered_enums) {
717                                 string locase = name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
718                                 if (!ht.Contains (locase)) {
719                                         ht.Add (locase, name_to_member [name]);
720                                         continue;
721                                 }
722  
723                                 EnumMember conflict = (EnumMember)ht [locase];
724                                 Report.SymbolRelatedToPreviousError (conflict);
725                                 conflict = (EnumMember)name_to_member [name];
726                                 Report.Error (3005, conflict.Location, "Identifier '{0}' differing only in case is not CLS-compliant", conflict.GetSignatureForError ());
727                         }
728                 }
729
730                 protected override bool VerifyClsCompliance (DeclSpace ds)
731                 {
732                         if (!base.VerifyClsCompliance (ds))
733                                 return false;
734
735                         VerifyClsName ();
736
737                         if (!AttributeTester.IsClsCompliant (UnderlyingType)) {
738                                 Report.Error (3009, Location, "'{0}': base type '{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
739                         }
740
741                         return true;
742                 }
743                 
744                 /// <summary>
745                 /// Returns full enum name.
746                 /// </summary>
747                 string GetEnumeratorName (string valueName)
748                 {
749                         return String.Concat (Name, ".", valueName);
750                 }
751
752                 //
753                 // IMemberFinder
754                 //
755                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
756                                                         MemberFilter filter, object criteria)
757                 {
758                         ArrayList members = new ArrayList ();
759
760                         if ((mt & MemberTypes.Field) != 0) {
761                                 if (criteria is string){
762                                         if (member_to_value [criteria] == null && current_ec != null){
763                                                 LookupEnumValue (current_ec, (string) criteria, Location.Null);
764                                         }
765                                 }
766                                 
767                                 foreach (FieldBuilder fb in field_builders)
768                                         if (filter (fb, criteria) == true)
769                                                 members.Add (fb);
770                         }
771
772                         return new MemberList (members);
773                 }
774
775                 public override MemberCache MemberCache {
776                         get {
777                                 return null;
778                         }
779                 }
780
781                 public ArrayList ValueNames {
782                         get {
783                                 return ordered_enums;
784                         }
785                 }
786
787                 // indexer
788                 public Expression this [string name] {
789                         get {
790                                 return (Expression) defined_names [name];
791                         }
792                 }
793
794                 public override AttributeTargets AttributeTargets {
795                         get {
796                                 return AttributeTargets.Enum;
797                         }
798                 }
799
800                 protected override void VerifyObsoleteAttribute()
801                 {
802                         // UnderlyingType is never obsolete
803                 }
804
805                 /// <summary>
806                 /// Returns ObsoleteAttribute for both enum type and enum member
807                 /// </summary>
808                 public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec, string identifier)
809                 {
810                         if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) {
811                                 return null;
812                         }
813
814                         ObsoleteAttribute oa = GetObsoleteAttribute (ec.DeclSpace);
815                         if (oa != null)
816                                 return oa;
817
818                         EnumMember em = (EnumMember)name_to_member [identifier];
819                         oa = em.GetObsoleteAttribute (ec);
820
821                         if (oa == null)
822                                 return null;
823
824                         caching_flags |= Flags.Obsolete;
825                         return oa;
826                 }
827         }
828 }