2004-12-08 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / attribute.cs
1 //
2 // attribute.cs: Attribute Handler
3 //
4 // Author: Ravi Pratap (ravi@ximian.com)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 //
12
13 using System;
14 using System.Diagnostics;
15 using System.Collections;
16 using System.Collections.Specialized;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Runtime.InteropServices;
20 using System.Runtime.CompilerServices;
21 using System.Security; 
22 using System.Security.Permissions;
23 using System.Text;
24
25 namespace Mono.CSharp {
26
27         /// <summary>
28         ///   Base class for objects that can have Attributes applied to them.
29         /// </summary>
30         public abstract class Attributable {
31                 /// <summary>
32                 ///   Attributes for this type
33                 /// </summary>
34                 Attributes attributes;
35
36                 public Attributable (Attributes attrs)
37                 {
38                         attributes = attrs;
39                 }
40
41                 public Attributes OptAttributes 
42                 {
43                         get {
44                                 return attributes;
45                         }
46                         set {
47                                 attributes = value;
48                         }
49                 }
50
51                 /// <summary>
52                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
53                 /// </summary>
54                 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
55
56                 /// <summary>
57                 /// Returns one AttributeTarget for this element.
58                 /// </summary>
59                 public abstract AttributeTargets AttributeTargets { get; }
60
61                 public abstract bool IsClsCompliaceRequired (DeclSpace ds);
62
63                 /// <summary>
64                 /// Gets list of valid attribute targets for explicit target declaration.
65                 /// The first array item is default target. Don't break this rule.
66                 /// </summary>
67                 public abstract string[] ValidAttributeTargets { get; }
68         };
69
70         public class Attribute {
71                 public readonly string ExplicitTarget;
72                 public AttributeTargets Target;
73
74                 public readonly string    Name;
75                 public readonly ArrayList Arguments;
76
77                 public readonly Location Location;
78
79                 public Type Type;
80
81                 // Is non-null if type is AttributeUsageAttribute
82                 AttributeUsageAttribute usage_attribute;
83
84                 public AttributeUsageAttribute UsageAttribute {
85                         get {
86                                 return usage_attribute;
87                         }
88                 }
89
90                 MethodImplOptions ImplOptions;
91                 UnmanagedType     UnmanagedType;
92                 CustomAttributeBuilder cb;
93         
94                 // non-null if named args present after Resolve () is called
95                 PropertyInfo [] prop_info_arr;
96                 FieldInfo [] field_info_arr;
97                 object [] field_values_arr;
98                 object [] prop_values_arr;
99                 object [] pos_values;
100
101                 static PtrHashtable usage_attr_cache = new PtrHashtable ();
102                 
103                 public Attribute (string target, string name, ArrayList args, Location loc)
104                 {
105                         Name = name;
106                         Arguments = args;
107                         Location = loc;
108                         ExplicitTarget = target;
109                 }
110
111                 void Error_InvalidNamedArgument (string name)
112                 {
113                         Report.Error (617, Location, "Invalid attribute argument: '{0}'.  Argument must be fields " +
114                                       "fields which are not readonly, static or const;  or read-write instance properties.",
115                                       Name);
116                 }
117
118                 static void Error_AttributeArgumentNotValid (Location loc)
119                 {
120                         Report.Error (182, loc,
121                                       "An attribute argument must be a constant expression, typeof " +
122                                       "expression or array creation expression");
123                 }
124
125                 /// <summary>
126                 /// This is rather hack. We report many emit attribute error with same error to be compatible with
127                 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
128                 /// </summary>
129                 public void Error_AttributeEmitError (string inner)
130                 {
131                         Report.Error (647, Location, "Error emitting '{0}' attribute because '{1}'", Name, inner);
132                 }
133
134                 public void Error_InvalidSecurityParent ()
135                 {
136                         Error_AttributeEmitError ("it is attached to invalid parent");
137                 }
138
139                 void Error_AttributeConstructorMismatch ()
140                 {
141                         Report.Error (-6, Location,
142                                       "Could not find a constructor for this argument list.");
143                 }
144
145                 /// <summary>
146                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
147                 /// </summary>
148                 protected virtual Type CheckAttributeType (EmitContext ec)
149                 {
150                         string NameAttribute = Name + "Attribute";
151
152                         Type t1 = ec.ResolvingTypeTree
153                                 ? ec.DeclSpace.FindType (Location, Name)
154                                 : RootContext.LookupType (ec.DeclSpace, Name, true, Location);
155
156                         // FIXME: Shouldn't do this for quoted attributes: [@A]
157                         Type t2 = ec.ResolvingTypeTree
158                                 ? ec.DeclSpace.FindType (Location, NameAttribute)
159                                 : RootContext.LookupType (ec.DeclSpace, NameAttribute, true, Location);
160
161                         String err0616 = null;
162
163                         if (t1 != null && ! t1.IsSubclassOf (TypeManager.attribute_type)) {
164                                 t1 = null;
165                                 err0616 = "'" + Name + "': is not an attribute class";
166                         }
167                         if (t2 != null && ! t2.IsSubclassOf (TypeManager.attribute_type)) {
168                                 t2 = null;
169                                 err0616 = (err0616 != null) 
170                                         ? "Neither '" + Name + "' nor '" + NameAttribute +"' is an attribute class"
171                                         : "'" + Name + "Attribute': is not an attribute class";
172                         }
173
174                         if (t1 != null && t2 != null) {
175                                 Report.Error(1614, Location, "'" + Name + "': is ambiguous; " 
176                                              + " use either '@" + Name + "' or '" + NameAttribute + "'");
177                                 return null;
178                         }
179                         if (t1 != null)
180                                 return t1;
181                         if (t2 != null)
182                                 return t2;
183
184                         if (err0616 != null) {
185                                 Report.Error (616, Location, err0616);
186                                 return null;
187                         }
188
189                         Report.Error (246, Location, 
190                                       "Could not find attribute '" + Name 
191                                       + "' (are you missing a using directive or an assembly reference ?)");
192
193                         return null;
194                 }
195
196                 public Type ResolveType (EmitContext ec)
197                 {
198                         if (Type == null)
199                                 Type = CheckAttributeType (ec);
200                         return Type;
201                 }
202
203                 /// <summary>
204                 ///   Validates the guid string
205                 /// </summary>
206                 bool ValidateGuid (string guid)
207                 {
208                         try {
209                                 new Guid (guid);
210                                 return true;
211                         } catch {
212                                 Report.Error (647, Location, "Format of GUID is invalid: " + guid);
213                                 return false;
214                         }
215                 }
216
217                 string GetFullMemberName (string member)
218                 {
219                         return Type.FullName + '.' + member;
220                 }
221
222                 //
223                 // Given an expression, if the expression is a valid attribute-argument-expression
224                 // returns an object that can be used to encode it, or null on failure.
225                 //
226                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result)
227                 {
228                         if (e is EnumConstant) {
229                                 if (RootContext.StdLib)
230                                         result = ((EnumConstant)e).GetValueAsEnumType ();
231                                 else
232                                         result = ((EnumConstant)e).GetValue ();
233
234                                 return true;
235                         }
236
237                         Constant constant = e as Constant;
238                         if (constant != null) {
239                                 if (e.Type != arg_type) {
240                                         constant = Const.ChangeType (loc, constant, arg_type);
241                                         if (constant == null) {
242                                                 result = null;
243                                                 Error_AttributeArgumentNotValid (loc);
244                                                 return false;
245                                         }
246                                 }
247                                 result = constant.GetValue ();
248                                 return true;
249                         } else if (e is TypeOf) {
250                                 result = ((TypeOf) e).TypeArg;
251                                 return true;
252                         } else if (e is ArrayCreation){
253                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();
254                                 if (result != null)
255                                         return true;
256                         } else if (e is EmptyCast) {
257                                 Expression child = ((EmptyCast)e).Child;
258                                 return GetAttributeArgumentExpression (child, loc, child.Type, out result);
259                         }
260
261                         result = null;
262                         Error_AttributeArgumentNotValid (loc);
263                         return false;
264                 }
265                 
266                 public CustomAttributeBuilder Resolve (EmitContext ec)
267                 {
268                         Type oldType = Type;
269                         
270                         // Sanity check.
271                         Type = CheckAttributeType (ec);
272
273                         if (oldType == null && Type == null)
274                                 return null;
275                         if (oldType != null && oldType != Type){
276                                 Report.Error (-27, Location,
277                                               "Attribute {0} resolved to different types at different times: {1} vs. {2}",
278                                               Name, oldType, Type);
279                                 return null;
280                         }
281
282                         if (Type.IsAbstract) {
283                                 Report.Error (653, Location, "Cannot apply attribute class '{0}' because it is abstract", Name);
284                                 return null;
285                         }
286
287                         bool MethodImplAttr = false;
288                         bool MarshalAsAttr = false;
289                         bool GuidAttr = false;
290                         bool usage_attr = false;
291
292                         bool DoCompares = true;
293
294                         //
295                         // If we are a certain special attribute, we
296                         // set the information accordingly
297                         //
298                         
299                         if (Type == TypeManager.attribute_usage_type)
300                                 usage_attr = true;
301                         else if (Type == TypeManager.methodimpl_attr_type)
302                                 MethodImplAttr = true;
303                         else if (Type == TypeManager.marshal_as_attr_type)
304                                 MarshalAsAttr = true;
305                         else if (Type == TypeManager.guid_attr_type)
306                                 GuidAttr = true;
307                         else
308                                 DoCompares = false;
309
310                         // Now we extract the positional and named arguments
311                         
312                         ArrayList pos_args = new ArrayList ();
313                         ArrayList named_args = new ArrayList ();
314                         int pos_arg_count = 0;
315                         
316                         if (Arguments != null) {
317                                 pos_args = (ArrayList) Arguments [0];
318                                 if (pos_args != null)
319                                         pos_arg_count = pos_args.Count;
320                                 if (Arguments.Count > 1)
321                                         named_args = (ArrayList) Arguments [1];
322                         }
323
324                         pos_values = new object [pos_arg_count];
325
326                         //
327                         // First process positional arguments 
328                         //
329
330                         int i;
331                         for (i = 0; i < pos_arg_count; i++) {
332                                 Argument a = (Argument) pos_args [i];
333                                 Expression e;
334
335                                 if (!a.Resolve (ec, Location))
336                                         return null;
337
338                                 e = a.Expr;
339
340                                 object val;
341                                 if (!GetAttributeArgumentExpression (e, Location, a.Type, out val))
342                                         return null;
343
344                                 pos_values [i] = val;
345
346                                 if (DoCompares){
347                                         if (usage_attr) {
348                                                 if ((int)val == 0) {
349                                                         Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute");
350                                                         return null;
351                                                 }
352                                                 usage_attribute = new AttributeUsageAttribute ((AttributeTargets)val);
353                                         } else if (MethodImplAttr) {
354                                                 this.ImplOptions = (MethodImplOptions) val;
355                                         } else if (GuidAttr){
356                                                 //
357                                                 // we will later check the validity of the type
358                                                 //
359                                                 if (val is string){
360                                                         if (!ValidateGuid ((string) val))
361                                                                 return null;
362                                                 }
363                                                 
364                                         } else if (MarshalAsAttr)
365                                                 this.UnmanagedType =
366                                                 (System.Runtime.InteropServices.UnmanagedType) val;
367                                 }
368                         }
369
370                         //
371                         // Now process named arguments
372                         //
373
374                         ArrayList field_infos = null;
375                         ArrayList prop_infos  = null;
376                         ArrayList field_values = null;
377                         ArrayList prop_values = null;
378
379                         if (named_args.Count > 0) {
380                                 field_infos = new ArrayList ();
381                                 prop_infos  = new ArrayList ();
382                                 field_values = new ArrayList ();
383                                 prop_values = new ArrayList ();
384                         }
385
386                         Hashtable seen_names = new Hashtable();
387                         
388                         for (i = 0; i < named_args.Count; i++) {
389                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
390                                 string member_name = (string) de.Key;
391                                 Argument a  = (Argument) de.Value;
392                                 Expression e;
393
394                                 if (seen_names.Contains(member_name)) {
395                                         Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument");
396                                         return null;
397                                 }                               
398                                 seen_names.Add(member_name, 1);
399                                 
400                                 if (!a.Resolve (ec, Location))
401                                         return null;
402
403                                 Expression member = Expression.MemberLookup (
404                                         ec, Type, member_name,
405                                         MemberTypes.Field | MemberTypes.Property,
406                                         BindingFlags.Public | BindingFlags.Instance,
407                                         Location);
408
409                                 if (member == null) {
410                                         member = Expression.MemberLookup (ec, Type, member_name,
411                                                 MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance,
412                                                 Location);
413
414                                         if (member != null) {
415                                                 Report.Error (122, Location, "'{0}' is inaccessible due to its protection level", GetFullMemberName (member_name));
416                                                 return null;
417                                         }
418                                 }
419
420                                 if (member == null){
421                                         Report.Error (117, Location, "Attribute `{0}' does not contain a definition for `{1}'",
422                                                       Type, member_name);
423                                         return null;
424                                 }
425                                 
426                                 if (!(member is PropertyExpr || member is FieldExpr)) {
427                                         Error_InvalidNamedArgument (member_name);
428                                         return null;
429                                 }
430
431                                 e = a.Expr;
432                                 if (member is PropertyExpr) {
433                                         PropertyExpr pe = (PropertyExpr) member;
434                                         PropertyInfo pi = pe.PropertyInfo;
435
436                                         if (!pi.CanWrite || !pi.CanRead) {
437                                                 Report.SymbolRelatedToPreviousError (pi);
438                                                 Error_InvalidNamedArgument (member_name);
439                                                 return null;
440                                         }
441
442                                         object value;
443                                         if (!GetAttributeArgumentExpression (e, Location, pi.PropertyType, out value))
444                                                 return null;
445
446                                         if (usage_attribute != null) {
447                                                 if (member_name == "AllowMultiple")
448                                                         usage_attribute.AllowMultiple = (bool) value;
449                                                 if (member_name == "Inherited")
450                                                         usage_attribute.Inherited = (bool) value;
451                                         }
452
453                                         prop_values.Add (value);
454                                         prop_infos.Add (pi);
455                                         
456                                 } else if (member is FieldExpr) {
457                                         FieldExpr fe = (FieldExpr) member;
458                                         FieldInfo fi = fe.FieldInfo;
459
460                                         if (fi.IsInitOnly) {
461                                                 Error_InvalidNamedArgument (member_name);
462                                                 return null;
463                                         }
464
465                                         object value;
466                                         if (!GetAttributeArgumentExpression (e, Location, fi.FieldType, out value))
467                                                 return null;
468
469                                         field_values.Add (value);                                       
470                                         field_infos.Add (fi);
471                                 }
472                         }
473
474                         Expression mg = Expression.MemberLookup (
475                                 ec, Type, ".ctor", MemberTypes.Constructor,
476                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
477                                 Location);
478
479                         if (mg == null) {
480                                 Error_AttributeConstructorMismatch ();
481                                 return null;
482                         }
483
484                         MethodBase constructor = Invocation.OverloadResolve (
485                                 ec, (MethodGroupExpr) mg, pos_args, false, Location);
486
487                         if (constructor == null) {
488                                 return null;
489                         }
490
491                         //
492                         // Now we perform some checks on the positional args as they
493                         // cannot be null for a constructor which expects a parameter
494                         // of type object
495                         //
496
497                         ParameterData pd = Invocation.GetParameterData (constructor);
498
499                         int last_real_param = pd.Count;
500                         if (pd.HasParams) {
501                                 // When the params is not filled we need to put one
502                                 if (last_real_param > pos_arg_count) {
503                                         object [] new_pos_values = new object [pos_arg_count + 1];
504                                         pos_values.CopyTo (new_pos_values, 0);
505                                         new_pos_values [pos_arg_count] = new object [] {} ;
506                                         pos_values = new_pos_values;
507                                 }
508                                 last_real_param--;
509                         }
510
511                         for (int j = 0; j < pos_arg_count; ++j) {
512                                 Argument a = (Argument) pos_args [j];
513                                 
514                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
515                                         Error_AttributeArgumentNotValid (Location);
516                                         return null;
517                                 }
518
519                                 if (j < last_real_param)
520                                         continue;
521                                 
522                                 if (j == last_real_param) {
523                                         object [] array = new object [pos_arg_count - last_real_param];
524                                         array [0] = pos_values [j];
525                                         pos_values [j] = array;
526                                         continue;
527                                 }
528
529                                 object [] params_array = (object []) pos_values [last_real_param];
530                                 params_array [j - last_real_param] = pos_values [j];
531                         }
532
533                         // Adjust the size of the pos_values if it had params
534                         if (last_real_param != pos_arg_count) {
535                                 object [] new_pos_values = new object [last_real_param + 1];
536                                 Array.Copy (pos_values, new_pos_values, last_real_param + 1);
537                                 pos_values = new_pos_values;
538                         }
539
540                         try {
541                                 if (named_args.Count > 0) {
542                                         prop_info_arr = new PropertyInfo [prop_infos.Count];
543                                         field_info_arr = new FieldInfo [field_infos.Count];
544                                         field_values_arr = new object [field_values.Count];
545                                         prop_values_arr = new object [prop_values.Count];
546
547                                         field_infos.CopyTo  (field_info_arr, 0);
548                                         field_values.CopyTo (field_values_arr, 0);
549
550                                         prop_values.CopyTo  (prop_values_arr, 0);
551                                         prop_infos.CopyTo   (prop_info_arr, 0);
552
553                                         cb = new CustomAttributeBuilder (
554                                                 (ConstructorInfo) constructor, pos_values,
555                                                 prop_info_arr, prop_values_arr,
556                                                 field_info_arr, field_values_arr);
557                                 }
558                                 else
559                                         cb = new CustomAttributeBuilder (
560                                                 (ConstructorInfo) constructor, pos_values);
561                         } catch (NullReferenceException) {
562                                 // 
563                                 // Don't know what to do here
564                                 //
565                                 Report.Warning (
566                                         -101, Location, "NullReferenceException while trying to create attribute." +
567                                         "Something's wrong!");
568                         } catch (Exception e) {
569                                 //
570                                 // Sample:
571                                 // using System.ComponentModel;
572                                 // [DefaultValue (CollectionChangeAction.Add)]
573                                 // class X { static void Main () {} }
574                                 //
575                                 Report.Warning (
576                                         -23, Location, "The compiler can not encode this attribute in .NET due to a bug in the .NET runtime. Try the Mono runtime. The exception was: " + e.Message);
577                         }
578                         
579                         return cb;
580                 }
581
582                 /// <summary>
583                 ///   Get a string containing a list of valid targets for the attribute 'attr'
584                 /// </summary>
585                 public string GetValidTargets ()
586                 {
587                         StringBuilder sb = new StringBuilder ();
588                         AttributeTargets targets = GetAttributeUsage ().ValidOn;
589
590                         if ((targets & AttributeTargets.Assembly) != 0)
591                                 sb.Append ("'assembly' ");
592
593                         if ((targets & AttributeTargets.Class) != 0)
594                                 sb.Append ("'class' ");
595
596                         if ((targets & AttributeTargets.Constructor) != 0)
597                                 sb.Append ("'constructor' ");
598
599                         if ((targets & AttributeTargets.Delegate) != 0)
600                                 sb.Append ("'delegate' ");
601
602                         if ((targets & AttributeTargets.Enum) != 0)
603                                 sb.Append ("'enum' ");
604
605                         if ((targets & AttributeTargets.Event) != 0)
606                                 sb.Append ("'event' ");
607
608                         if ((targets & AttributeTargets.Field) != 0)
609                                 sb.Append ("'field' ");
610
611                         if ((targets & AttributeTargets.Interface) != 0)
612                                 sb.Append ("'interface' ");
613
614                         if ((targets & AttributeTargets.Method) != 0)
615                                 sb.Append ("'method' ");
616
617                         if ((targets & AttributeTargets.Module) != 0)
618                                 sb.Append ("'module' ");
619
620                         if ((targets & AttributeTargets.Parameter) != 0)
621                                 sb.Append ("'parameter' ");
622
623                         if ((targets & AttributeTargets.Property) != 0)
624                                 sb.Append ("'property' ");
625
626                         if ((targets & AttributeTargets.ReturnValue) != 0)
627                                 sb.Append ("'return' ");
628
629                         if ((targets & AttributeTargets.Struct) != 0)
630                                 sb.Append ("'struct' ");
631
632                         return sb.ToString ();
633
634                 }
635
636                 /// <summary>
637                 /// Returns AttributeUsage attribute for this type
638                 /// </summary>
639                 public AttributeUsageAttribute GetAttributeUsage ()
640                 {
641                         AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute;
642                         if (ua != null)
643                                 return ua;
644
645                         Class attr_class = TypeManager.LookupClass (Type);
646
647                         if (attr_class == null) {
648                                 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
649                                 ua = (AttributeUsageAttribute)usage_attr [0];
650                                 usage_attr_cache.Add (Type, ua);
651                                 return ua;
652                         }
653                 
654                         return attr_class.AttributeUsage;
655                 }
656
657                 /// <summary>
658                 /// Returns custom name of indexer
659                 /// </summary>
660                 public string GetIndexerAttributeValue (EmitContext ec)
661                 {
662                         if (pos_values == null) {
663                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
664                                 // But because a lot of attribute class code must be rewritten will be better to wait...
665                                 Resolve (ec);
666                         }
667
668                         return pos_values [0] as string;
669                 }
670
671                 /// <summary>
672                 /// Returns condition of ConditionalAttribute
673                 /// </summary>
674                 public string GetConditionalAttributeValue (DeclSpace ds)
675                 {
676                         if (pos_values == null) {
677                                 EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
678
679                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
680                                 // But because a lot of attribute class code must be rewritten will be better to wait...
681                                 Resolve (ec);
682                         }
683
684                         // Some error occurred
685                         if (pos_values [0] == null)
686                                 return null;
687
688                         return (string)pos_values [0];
689                 }
690
691                 /// <summary>
692                 /// Creates the instance of ObsoleteAttribute from this attribute instance
693                 /// </summary>
694                 public ObsoleteAttribute GetObsoleteAttribute (DeclSpace ds)
695                 {
696                         if (pos_values == null) {
697                                 EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
698
699                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
700                                 // But because a lot of attribute class code must be rewritten will be better to wait...
701                                 Resolve (ec);
702                         }
703
704                         // Some error occurred
705                         if (pos_values == null)
706                                 return null;
707
708                         if (pos_values.Length == 0)
709                                 return new ObsoleteAttribute ();
710
711                         if (pos_values.Length == 1)
712                                 return new ObsoleteAttribute ((string)pos_values [0]);
713
714                         return new ObsoleteAttribute ((string)pos_values [0], (bool)pos_values [1]);
715                 }
716
717                 /// <summary>
718                 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
719                 /// before ApplyAttribute. We need to resolve the arguments.
720                 /// This situation occurs when class deps is differs from Emit order.  
721                 /// </summary>
722                 public bool GetClsCompliantAttributeValue (DeclSpace ds)
723                 {
724                         if (pos_values == null) {
725                                 EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
726
727                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
728                                 // But because a lot of attribute class code must be rewritten will be better to wait...
729                                 Resolve (ec);
730                         }
731
732                         // Some error occurred
733                         if (pos_values [0] == null)
734                                 return false;
735
736                         return (bool)pos_values [0];
737                 }
738
739                 /// <summary>
740                 /// Tests permitted SecurityAction for assembly or other types
741                 /// </summary>
742                 public bool CheckSecurityActionValidity (bool for_assembly)
743                 {
744                         SecurityAction action  = GetSecurityActionValue ();
745
746                         if ((action == SecurityAction.RequestMinimum || action == SecurityAction.RequestOptional || action == SecurityAction.RequestRefuse) && for_assembly)
747                                 return true;
748
749                         if (!for_assembly) {
750                                 if (action < SecurityAction.Demand || action > SecurityAction.InheritanceDemand) {
751                                         Error_AttributeEmitError ("SecurityAction is out of range");
752                                         return false;
753                                 }
754
755                                 if ((action != SecurityAction.RequestMinimum && action != SecurityAction.RequestOptional && action != SecurityAction.RequestRefuse) && !for_assembly)
756                                         return true;
757                         }
758
759                         Error_AttributeEmitError (String.Concat ("SecurityAction '", action, "' is not valid for this declaration"));
760                         return false;
761                 }
762
763                 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
764                 {
765                         return (SecurityAction)pos_values [0];
766                 }
767
768                 /// <summary>
769                 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
770                 /// </summary>
771                 /// <returns></returns>
772                 public void ExtractSecurityPermissionSet (ListDictionary permissions)
773                 {
774                         if (TypeManager.LookupDeclSpace (Type) != null && RootContext.StdLib) {
775                                 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
776                                 return;
777                         }
778
779                         SecurityAttribute sa;
780                         // For all assemblies except corlib we can avoid all hacks
781                         if (RootContext.StdLib) {
782                                 sa = (SecurityAttribute) Activator.CreateInstance (Type, pos_values);
783
784                                 if (prop_info_arr != null) {
785                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
786                                                 PropertyInfo pi = prop_info_arr [i];
787                                                 pi.SetValue (sa, prop_values_arr [i], null);
788                                         }
789                                 }
790                         } else {
791                                 Type temp_type = Type.GetType (Type.FullName);
792                                 // HACK: All mscorlib attributes have same ctor syntax
793                                 sa = (SecurityAttribute) Activator.CreateInstance (temp_type, new object[] { GetSecurityActionValue () } );
794
795                                 // All types are from newly created corlib but for invocation with old we need to convert them
796                                 if (prop_info_arr != null) {
797                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
798                                                 PropertyInfo emited_pi = prop_info_arr [i];
799                                                 PropertyInfo pi = temp_type.GetProperty (emited_pi.Name, emited_pi.PropertyType);
800
801                                                 object old_instance = pi.PropertyType.IsEnum ?
802                                                         System.Enum.ToObject (pi.PropertyType, prop_values_arr [i]) :
803                                                         prop_values_arr [i];
804
805                                                 pi.SetValue (sa, old_instance, null);
806                                         }
807                                 }
808                         }
809
810                         IPermission perm = sa.CreatePermission ();
811                         SecurityAction action;
812
813                         // IS is correct because for corlib we are using an instance from old corlib
814                         if (perm is System.Security.CodeAccessPermission) {
815                                 action = GetSecurityActionValue ();
816                         } else {
817                                 switch (GetSecurityActionValue ()) {
818                                         case SecurityAction.Demand:
819                                                 action = (SecurityAction)13;
820                                                 break;
821                                         case SecurityAction.LinkDemand:
822                                                 action = (SecurityAction)14;
823                                                 break;
824                                         case SecurityAction.InheritanceDemand:
825                                                 action = (SecurityAction)15;
826                                                 break;
827                                         default:
828                                                 Error_AttributeEmitError ("Invalid SecurityAction for non-Code Access Security permission");
829                                                 return;
830                                 }
831                         }
832
833                         PermissionSet ps = (PermissionSet)permissions [action];
834                         if (ps == null) {
835                                 ps = new PermissionSet (PermissionState.None);
836                                 permissions.Add (action, ps);
837                         }
838                         ps.AddPermission (sa.CreatePermission ());
839                 }
840
841                 object GetValue (object value)
842                 {
843                         if (value is EnumConstant)
844                                 return ((EnumConstant) value).GetValue ();
845                         else
846                                 return value;                           
847                 }
848
849                 public object GetPositionalValue (int i)
850                 {
851                         return (pos_values == null) ? null : pos_values[i];
852                 }
853
854                 object GetFieldValue (string name)
855                 {
856                         int i;
857                         if (field_info_arr == null)
858                                 return null;
859                         i = 0;
860                         foreach (FieldInfo fi in field_info_arr) {
861                                 if (fi.Name == name)
862                                         return GetValue (field_values_arr [i]);
863                                 i++;
864                         }
865                         return null;
866                 }
867
868                 public UnmanagedMarshal GetMarshal (Attributable attr)
869                 {
870                         object value = GetFieldValue ("SizeParamIndex");
871                         if (value != null && UnmanagedType != UnmanagedType.LPArray) {
872                                 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
873                                 return null;
874                         }
875
876                         object o = GetFieldValue ("ArraySubType");
877                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
878                         
879                         switch (UnmanagedType) {
880                         case UnmanagedType.CustomMarshaler:
881                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
882                                                                        BindingFlags.Static | BindingFlags.Public);
883                                 if (define_custom == null) {
884                                         Report.RuntimeMissingSupport (Location, "set marshal info");
885                                         return null;
886                                 }
887                                 
888                                 object [] args = new object [4];
889                                 args [0] = GetFieldValue ("MarshalTypeRef");
890                                 args [1] = GetFieldValue ("MarshalCookie");
891                                 args [2] = GetFieldValue ("MarshalType");
892                                 args [3] = Guid.Empty;
893                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);
894                                 
895                         case UnmanagedType.LPArray:                             
896                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);
897                         
898                         case UnmanagedType.SafeArray:
899                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
900                         
901                         case UnmanagedType.ByValArray:
902                                 FieldMember fm = attr as FieldMember;
903                                 if (fm == null) {
904                                         Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
905                                         return null;
906                                 }
907                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
908                         
909                         case UnmanagedType.ByValTStr:
910                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
911                         
912                         default:
913                                 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
914                         }
915                 }
916
917                 public bool IsInternalCall
918                 {
919                         get { return ImplOptions == MethodImplOptions.InternalCall; }
920                 }
921
922                 /// <summary>
923                 /// Emit attribute for Attributable symbol
924                 /// </summary>
925                 public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr)
926                 {
927                         CustomAttributeBuilder cb = Resolve (ec);
928                         if (cb == null)
929                                 return;
930
931                         AttributeUsageAttribute usage_attr = GetAttributeUsage ();
932                         if ((usage_attr.ValidOn & Target) == 0) {
933                                 Report.Error (592, Location, "Attribute '{0}' is not valid on this declaration type. It is valid on {1} declarations only.", Name, GetValidTargets ());
934                                 return;
935                         }
936
937                         ias.ApplyAttributeBuilder (this, cb);
938
939                         if (!usage_attr.AllowMultiple) {
940                                 ArrayList emitted_targets = (ArrayList)emitted_attr [Type];
941                                 if (emitted_targets == null) {
942                                         emitted_targets = new ArrayList ();
943                                         emitted_attr.Add (Type, emitted_targets);
944                                 } else if (emitted_targets.Contains (Target)) {
945                                         Report.Error (579, Location, "Duplicate '" + Name + "' attribute");
946                                         return;
947                                 }
948                                 emitted_targets.Add (Target);
949                         }
950
951                         if (!RootContext.VerifyClsCompliance)
952                                 return;
953
954                         // Here we are testing attribute arguments for array usage (error 3016)
955                         if (ias.IsClsCompliaceRequired (ec.DeclSpace)) {
956                                 if (Arguments == null)
957                                         return;
958
959                                 ArrayList pos_args = (ArrayList) Arguments [0];
960                                 if (pos_args != null) {
961                                         foreach (Argument arg in pos_args) { 
962                                                 // Type is undefined (was error 246)
963                                                 if (arg.Type == null)
964                                                         return;
965
966                                                 if (arg.Type.IsArray) {
967                                                         Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
968                                                         return;
969                                                 }
970                                         }
971                                 }
972                         
973                                 if (Arguments.Count < 2)
974                                         return;
975                         
976                                 ArrayList named_args = (ArrayList) Arguments [1];
977                                 foreach (DictionaryEntry de in named_args) {
978                                         Argument arg  = (Argument) de.Value;
979
980                                         // Type is undefined (was error 246)
981                                         if (arg.Type == null)
982                                                 return;
983
984                                         if (arg.Type.IsArray) {
985                                                 Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
986                                                 return;
987                                         }
988                                 }
989                         }
990                 }
991
992                 public object GetValue (EmitContext ec, Constant c, Type target)
993                 {
994                         if (Convert.ImplicitConversionExists (ec, c, target))
995                                 return c.GetValue ();
996
997                         Convert.Error_CannotImplicitConversion (Location, c.Type, target);
998                         return null;
999                 }
1000                 
1001                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
1002                                                           MethodAttributes flags, Type ret_type, Type [] param_types)
1003                 {
1004                         //
1005                         // We extract from the attribute the information we need 
1006                         //
1007
1008                         if (Arguments == null) {
1009                                 Console.WriteLine ("Internal error : this is not supposed to happen !");
1010                                 return null;
1011                         }
1012
1013                         ResolveType (ec);
1014                         if (Type == null)
1015                                 return null;
1016                         
1017                         ArrayList named_args = new ArrayList ();
1018                         
1019                         ArrayList pos_args = (ArrayList) Arguments [0];
1020                         if (Arguments.Count > 1)
1021                                 named_args = (ArrayList) Arguments [1];
1022                         
1023
1024                         string dll_name = null;
1025                         
1026                         Argument tmp = (Argument) pos_args [0];
1027
1028                         if (!tmp.Resolve (ec, Location))
1029                                 return null;
1030                         
1031                         if (tmp.Expr is Constant)
1032                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
1033                         else { 
1034                                 Error_AttributeArgumentNotValid (Location);
1035                                 return null;
1036                         }
1037
1038                         // Now we process the named arguments
1039                         CallingConvention cc = CallingConvention.Winapi;
1040                         CharSet charset = CharSet.Ansi;
1041                         bool preserve_sig = true;
1042 #if FIXME
1043                         bool exact_spelling = false;
1044 #endif
1045                         bool set_last_err = false;
1046                         string entry_point = null;
1047
1048                         for (int i = 0; i < named_args.Count; i++) {
1049
1050                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
1051
1052                                 string member_name = (string) de.Key;
1053                                 Argument a  = (Argument) de.Value;
1054
1055                                 if (!a.Resolve (ec, Location))
1056                                         return null;
1057
1058                                 Expression member = Expression.MemberLookup (
1059                                         ec, Type, member_name, 
1060                                         MemberTypes.Field | MemberTypes.Property,
1061                                         BindingFlags.Public | BindingFlags.Instance,
1062                                         Location);
1063
1064                                 if (member == null || !(member is FieldExpr)) {
1065                                         Error_InvalidNamedArgument (member_name);
1066                                         return null;
1067                                 }
1068
1069                                 if (member is FieldExpr) {
1070                                         FieldExpr fe = (FieldExpr) member;
1071                                         FieldInfo fi = fe.FieldInfo;
1072
1073                                         if (fi.IsInitOnly) {
1074                                                 Error_InvalidNamedArgument (member_name);
1075                                                 return null;
1076                                         }
1077
1078                                         if (a.Expr is Constant) {
1079                                                 Constant c = (Constant) a.Expr;
1080
1081                                                 try {
1082                                                         if (member_name == "CallingConvention"){
1083                                                                 object val = GetValue (ec, c, typeof (CallingConvention));
1084                                                                 if (val == null)
1085                                                                         return null;
1086                                                                 cc = (CallingConvention) val;
1087                                                         } else if (member_name == "CharSet"){
1088                                                                 charset = (CharSet) c.GetValue ();
1089                                                         } else if (member_name == "EntryPoint")
1090                                                                 entry_point = (string) c.GetValue ();
1091                                                         else if (member_name == "SetLastError")
1092                                                                 set_last_err = (bool) c.GetValue ();
1093 #if FIXME
1094                                                         else if (member_name == "ExactSpelling")
1095                                                                 exact_spelling = (bool) c.GetValue ();
1096 #endif
1097                                                         else if (member_name == "PreserveSig")
1098                                                                 preserve_sig = (bool) c.GetValue ();
1099                                                 } catch (InvalidCastException){
1100                                                         Error_InvalidNamedArgument (member_name);
1101                                                         Error_AttributeArgumentNotValid (Location);
1102                                                 }
1103                                         } else { 
1104                                                 Error_AttributeArgumentNotValid (Location);
1105                                                 return null;
1106                                         }
1107                                         
1108                                 }
1109                         }
1110
1111                         if (entry_point == null)
1112                                 entry_point = name;
1113                         if (set_last_err)
1114                                 charset = (CharSet)((int)charset | 0x40);
1115                         
1116                         MethodBuilder mb = builder.DefinePInvokeMethod (
1117                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
1118                                 CallingConventions.Standard,
1119                                 ret_type,
1120                                 param_types,
1121                                 cc,
1122                                 charset);
1123
1124                         if (preserve_sig)
1125                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
1126                         
1127                         return mb;
1128                 }
1129
1130                 private Expression GetValue () 
1131                 {
1132                         if ((Arguments == null) || (Arguments.Count < 1))
1133                                 return null;
1134                         ArrayList al = (ArrayList) Arguments [0];
1135                         if ((al == null) || (al.Count < 1))
1136                                 return null;
1137                         Argument arg = (Argument) al [0];
1138                         if ((arg == null) || (arg.Expr == null))
1139                                 return null;
1140                         return arg.Expr;
1141                 }
1142
1143                 public string GetString () 
1144                 {
1145                         Expression e = GetValue ();
1146                         if (e is StringLiteral)
1147                                 return (e as StringLiteral).Value;
1148                         return null;
1149                 }
1150
1151                 public bool GetBoolean () 
1152                 {
1153                         Expression e = GetValue ();
1154                         if (e is BoolLiteral)
1155                                 return (e as BoolLiteral).Value;
1156                         return false;
1157                 }
1158         }
1159         
1160
1161         /// <summary>
1162         /// For global attributes (assembly, module) we need special handling.
1163         /// Attributes can be located in the several files
1164         /// </summary>
1165         public class GlobalAttribute: Attribute
1166         {
1167                 public readonly NamespaceEntry ns;
1168
1169                 public GlobalAttribute (TypeContainer container, string target, string name, ArrayList args, Location loc):
1170                         base (target, name, args, loc)
1171                 {
1172                         ns = container.NamespaceEntry;
1173                 }
1174
1175                 protected override Type CheckAttributeType (EmitContext ec)
1176                 {
1177                         // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
1178                         // each time a new file is parsed.  However, we need to use the NamespaceEntry
1179                         // in effect where the attribute was used.  Since code elsewhere cannot assume
1180                         // that the NamespaceEntry is right, just overwrite it.
1181                         //
1182                         // FIXME: Check every place the NamespaceEntry of RootContext.Tree.Types is used
1183                         //        to ensure the right one is used.
1184                         if (ec.DeclSpace == RootContext.Tree.Types)
1185                                 ec.DeclSpace.NamespaceEntry = ns;
1186
1187                         return base.CheckAttributeType (ec);
1188                 }
1189         }
1190
1191         public class Attributes {
1192                 public ArrayList Attrs;
1193
1194                 public Attributes (Attribute a)
1195                 {
1196                         Attrs = new ArrayList ();
1197                         Attrs.Add (a);
1198                 }
1199
1200                 public Attributes (ArrayList attrs)
1201                 {
1202                         Attrs = attrs;
1203                 }
1204
1205                 public void AddAttributes (ArrayList attrs)
1206                 {
1207                         Attrs.AddRange (attrs);
1208                 }
1209
1210                 /// <summary>
1211                 /// Checks whether attribute target is valid for the current element
1212                 /// </summary>
1213                 public bool CheckTargets (Attributable member)
1214                 {
1215                         string[] valid_targets = member.ValidAttributeTargets;
1216                         foreach (Attribute a in Attrs) {
1217                                 if (a.ExplicitTarget == null || a.ExplicitTarget == valid_targets [0]) {
1218                                         a.Target = member.AttributeTargets;
1219                                         continue;
1220                                 }
1221
1222                                 // TODO: we can skip the first item
1223                                 if (((IList) valid_targets).Contains (a.ExplicitTarget)) {
1224                                         switch (a.ExplicitTarget) {
1225                                                 case "return": a.Target = AttributeTargets.ReturnValue; continue;
1226                                                 case "param": a.Target = AttributeTargets.Parameter; continue;
1227                                                 case "field": a.Target = AttributeTargets.Field; continue;
1228                                                 case "method": a.Target = AttributeTargets.Method; continue;
1229                                                 case "property": a.Target = AttributeTargets.Property; continue;
1230                                         }
1231                                         throw new InternalErrorException ("Unknown explicit target: " + a.ExplicitTarget);
1232                                 }
1233
1234                                 StringBuilder sb = new StringBuilder ();
1235                                 foreach (string s in valid_targets) {
1236                                         sb.Append (s);
1237                                         sb.Append (", ");
1238                                 }
1239                                 sb.Remove (sb.Length - 2, 2);
1240                                 Report.Error (657, a.Location, "'{0}' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are '{1}'", a.ExplicitTarget, sb.ToString ());
1241                                 return false;
1242                         }
1243                         return true;
1244                 }
1245
1246                 public Attribute Search (Type t, EmitContext ec)
1247                 {
1248                         foreach (Attribute a in Attrs) {
1249                                 if (a.ResolveType (ec) == t)
1250                                         return a;
1251                         }
1252                         return null;
1253                 }
1254
1255                 /// <summary>
1256                 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1257                 /// </summary>
1258                 public Attribute[] SearchMulti (Type t, EmitContext ec)
1259                 {
1260                         ArrayList ar = null;
1261
1262                         foreach (Attribute a in Attrs) {
1263                                 if (a.ResolveType (ec) == t) {
1264                                         if (ar == null)
1265                                                 ar = new ArrayList ();
1266                                         ar.Add (a);
1267                                 }
1268                         }
1269
1270                         return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
1271                 }
1272
1273                 public void Emit (EmitContext ec, Attributable ias)
1274                 {
1275                         if (!CheckTargets (ias))
1276                                 return;
1277
1278                         ListDictionary ld = new ListDictionary ();
1279
1280                         foreach (Attribute a in Attrs)
1281                                 a.Emit (ec, ias, ld);
1282                 }
1283
1284                 public bool Contains (Type t, EmitContext ec)
1285                 {
1286                         return Search (t, ec) != null;
1287                 }
1288         }
1289
1290         /// <summary>
1291         /// Helper class for attribute verification routine.
1292         /// </summary>
1293         sealed class AttributeTester
1294         {
1295                 static PtrHashtable analyzed_types = new PtrHashtable ();
1296                 static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
1297                 static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
1298                 static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
1299
1300                 private AttributeTester ()
1301                 {
1302                 }
1303
1304                 /// <summary>
1305                 /// Returns true if parameters of two compared methods are CLS-Compliant.
1306                 /// It tests differing only in ref or out, or in array rank.
1307                 /// </summary>
1308                 public static bool AreOverloadedMethodParamsClsCompliant (Type[] types_a, Type[] types_b) 
1309                 {
1310                         if (types_a == null || types_b == null)
1311                                 return true;
1312
1313                         if (types_a.Length != types_b.Length)
1314                                 return true;
1315
1316                         for (int i = 0; i < types_b.Length; ++i) {
1317                                 Type aType = types_a [i];
1318                                 Type bType = types_b [i];
1319
1320                                 if (aType.IsArray && bType.IsArray && aType.GetArrayRank () != bType.GetArrayRank () && aType.GetElementType () == bType.GetElementType ()) {
1321                                         return false;
1322                                 }
1323
1324                                 Type aBaseType = aType;
1325                                 bool is_either_ref_or_out = false;
1326
1327                                 if (aType.IsByRef || aType.IsPointer) {
1328                                         aBaseType = aType.GetElementType ();
1329                                         is_either_ref_or_out = true;
1330                                 }
1331
1332                                 Type bBaseType = bType;
1333                                 if (bType.IsByRef || bType.IsPointer) 
1334                                 {
1335                                         bBaseType = bType.GetElementType ();
1336                                         is_either_ref_or_out = !is_either_ref_or_out;
1337                                 }
1338
1339                                 if (aBaseType != bBaseType)
1340                                         continue;
1341
1342                                 if (is_either_ref_or_out)
1343                                         return false;
1344                         }
1345                         return true;
1346                 }
1347
1348                 /// <summary>
1349                 /// Goes through all parameters and test if they are CLS-Compliant.
1350                 /// </summary>
1351                 public static bool AreParametersCompliant (Parameter[] fixedParameters, Location loc)
1352                 {
1353                         if (fixedParameters == null)
1354                                 return true;
1355
1356                         foreach (Parameter arg in fixedParameters) {
1357                                 if (!AttributeTester.IsClsCompliant (arg.ParameterType)) {
1358                                         Report.Error (3001, loc, "Argument type '{0}' is not CLS-compliant", arg.GetSignatureForError ());
1359                                         return false;
1360                                 }
1361                         }
1362                         return true;
1363                 }
1364
1365
1366                 /// <summary>
1367                 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1368                 /// </summary>
1369                 public static bool IsClsCompliant (Type type) 
1370                 {
1371                         if (type == null)
1372                                 return true;
1373
1374                         object type_compliance = analyzed_types[type];
1375                         if (type_compliance != null)
1376                                 return type_compliance == TRUE;
1377
1378                         if (type.IsPointer) {
1379                                 analyzed_types.Add (type, null);
1380                                 return false;
1381                         }
1382
1383                         bool result;
1384                         if (type.IsArray || type.IsByRef)       {
1385                                 result = IsClsCompliant (TypeManager.GetElementType (type));
1386                         } else {
1387                                 result = AnalyzeTypeCompliance (type);
1388                         }
1389                         analyzed_types.Add (type, result ? TRUE : FALSE);
1390                         return result;
1391                 }                
1392
1393                 static object TRUE = new object ();
1394                 static object FALSE = new object ();
1395
1396                 public static void VerifyModulesClsCompliance ()
1397                 {
1398                         Module[] modules = TypeManager.Modules;
1399                         if (modules == null)
1400                                 return;
1401
1402                         // The first module is generated assembly
1403                         for (int i = 1; i < modules.Length; ++i) {
1404                                 Module module = modules [i];
1405                                 if (!IsClsCompliant (module)) {
1406                                         Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute to match the assembly", module.Name);
1407                                         return;
1408                                 }
1409                         }
1410                 }
1411
1412                 /// <summary>
1413                 /// Tests container name for CLS-Compliant name (differing only in case)
1414                 /// </summary>
1415                 public static void VerifyTopLevelNameClsCompliance ()
1416                 {
1417                         Hashtable locase_table = new Hashtable ();
1418
1419                         // Convert imported type names to lower case and ignore not cls compliant
1420                         foreach (DictionaryEntry de in TypeManager.all_imported_types) {
1421                                 Type t = (Type)de.Value;
1422                                 if (!AttributeTester.IsClsCompliant (t))
1423                                         continue;
1424
1425                                 locase_table.Add (((string)de.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture), t);
1426                         }
1427
1428                         foreach (DictionaryEntry de in RootContext.Tree.Decls) {
1429                                 DeclSpace decl = (DeclSpace)de.Value;
1430                                 if (!decl.IsClsCompliaceRequired (decl))
1431                                         continue;
1432
1433                                 string lcase = decl.Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
1434                                 if (!locase_table.Contains (lcase)) {
1435                                         locase_table.Add (lcase, decl);
1436                                         continue;
1437                                 }
1438
1439                                 object conflict = locase_table [lcase];
1440                                 if (conflict is Type)
1441                                         Report.SymbolRelatedToPreviousError ((Type)conflict);
1442                                 else
1443                                         Report.SymbolRelatedToPreviousError ((MemberCore)conflict);
1444
1445                                 Report.Error (3005, decl.Location, "Identifier '{0}' differing only in case is not CLS-compliant", decl.GetSignatureForError ());
1446                         }
1447                 }
1448
1449                 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider) 
1450                 {
1451                         object[] CompliantAttribute = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1452                         if (CompliantAttribute.Length == 0)
1453                                 return false;
1454
1455                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1456                 }
1457
1458                 static bool AnalyzeTypeCompliance (Type type)
1459                 {
1460                         DeclSpace ds = TypeManager.LookupDeclSpace (type);
1461                         if (ds != null) {
1462                                 return ds.IsClsCompliaceRequired (ds.Parent);
1463                         }
1464
1465                         object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1466                         if (CompliantAttribute.Length == 0) 
1467                                 return IsClsCompliant (type.Assembly);
1468
1469                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1470                 }
1471
1472                 /// <summary>
1473                 /// Returns instance of ObsoleteAttribute when type is obsolete
1474                 /// </summary>
1475                 public static ObsoleteAttribute GetObsoleteAttribute (Type type)
1476                 {
1477                         object type_obsolete = analyzed_types_obsolete [type];
1478                         if (type_obsolete == FALSE)
1479                                 return null;
1480
1481                         if (type_obsolete != null)
1482                                 return (ObsoleteAttribute)type_obsolete;
1483
1484                         ObsoleteAttribute result = null;
1485                         if (type.IsByRef || type.IsArray || type.IsPointer) {
1486                                 result = GetObsoleteAttribute (TypeManager.GetElementType (type));
1487                         } else {
1488                                 DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
1489
1490                                 // Type is external, we can get attribute directly
1491                                 if (type_ds == null) {
1492                                         object[] attribute = type.GetCustomAttributes (TypeManager.obsolete_attribute_type, false);
1493                                         if (attribute.Length == 1)
1494                                                 result = (ObsoleteAttribute)attribute [0];
1495                                 } else {
1496                                         result = type_ds.GetObsoleteAttribute (type_ds);
1497                                 }
1498                         }
1499
1500                         analyzed_types_obsolete.Add (type, result == null ? FALSE : result);
1501                         return result;
1502                 }
1503
1504                 /// <summary>
1505                 /// Returns instance of ObsoleteAttribute when method is obsolete
1506                 /// </summary>
1507                 public static ObsoleteAttribute GetMethodObsoleteAttribute (MethodBase mb)
1508                 {
1509                         IMethodData mc = TypeManager.GetMethod (mb);
1510                         if (mc != null) 
1511                                 return mc.GetObsoleteAttribute ();
1512
1513                         // compiler generated methods are not registered by AddMethod
1514                         if (mb.DeclaringType is TypeBuilder)
1515                                 return null;
1516
1517                         return GetMemberObsoleteAttribute (mb);
1518                 }
1519
1520                 /// <summary>
1521                 /// Returns instance of ObsoleteAttribute when member is obsolete
1522                 /// </summary>
1523                 public static ObsoleteAttribute GetMemberObsoleteAttribute (MemberInfo mi)
1524                 {
1525                         object type_obsolete = analyzed_member_obsolete [mi];
1526                         if (type_obsolete == FALSE)
1527                                 return null;
1528
1529                         if (type_obsolete != null)
1530                                 return (ObsoleteAttribute)type_obsolete;
1531
1532                         ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false) as ObsoleteAttribute;
1533                         analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
1534                         return oa;
1535                 }
1536
1537                 /// <summary>
1538                 /// Common method for Obsolete error/warning reporting.
1539                 /// </summary>
1540                 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc)
1541                 {
1542                         if (oa.IsError) {
1543                                 Report.Error (619, loc, "'{0}' is obsolete: '{1}'", member, oa.Message);
1544                                 return;
1545                         }
1546
1547                         if (oa.Message == null) {
1548                                 Report.Warning (612, loc, "'{0}' is obsolete", member);
1549                                 return;
1550                         }
1551                         if (RootContext.WarningLevel >= 2)
1552                                 Report.Warning (618, loc, "'{0}' is obsolete: '{1}'", member, oa.Message);
1553                 }
1554
1555                 public static bool IsConditionalMethodExcluded (MethodBase mb)
1556                 {
1557                         object excluded = analyzed_method_excluded [mb];
1558                         if (excluded != null)
1559                                 return excluded == TRUE ? true : false;
1560                         
1561                         ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[];
1562                         if (attrs.Length == 0) {
1563                                 analyzed_method_excluded.Add (mb, FALSE);
1564                                 return false;
1565                         }
1566
1567                         foreach (ConditionalAttribute a in attrs) {
1568                                 if (RootContext.AllDefines.Contains (a.ConditionString)) {
1569                                         analyzed_method_excluded.Add (mb, FALSE);
1570                                         return false;
1571                                 }
1572                         }
1573                         analyzed_method_excluded.Add (mb, TRUE);
1574                         return true;
1575                 }
1576         }
1577 }