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