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