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