2005-10-06 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / gmcs / 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 using System.IO;
25
26 namespace Mono.CSharp {
27
28         /// <summary>
29         ///   Base class for objects that can have Attributes applied to them.
30         /// </summary>
31         public abstract class Attributable {
32                 /// <summary>
33                 ///   Attributes for this type
34                 /// </summary>
35                 Attributes attributes;
36
37                 public Attributable (Attributes attrs)
38                 {
39                         attributes = attrs;
40                 }
41
42                 public Attributes OptAttributes 
43                 {
44                         get {
45                                 return attributes;
46                         }
47                         set {
48                                 attributes = value;
49                         }
50                 }
51
52                 /// <summary>
53                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
54                 /// </summary>
55                 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
56
57                 /// <summary>
58                 /// Returns one AttributeTarget for this element.
59                 /// </summary>
60                 public abstract AttributeTargets AttributeTargets { get; }
61
62                 public abstract bool IsClsComplianceRequired (DeclSpace ds);
63
64                 /// <summary>
65                 /// Gets list of valid attribute targets for explicit target declaration.
66                 /// The first array item is default target. Don't break this rule.
67                 /// </summary>
68                 public abstract string[] ValidAttributeTargets { get; }
69         };
70
71         public class Attribute {
72                 public readonly string ExplicitTarget;
73                 public AttributeTargets Target;
74
75                 // TODO: remove this member
76                 public readonly string    Name;
77                 public readonly Expression LeftExpr;
78                 public readonly string Identifier;
79
80                 public readonly ArrayList Arguments;
81
82                 public readonly Location Location;
83
84                 public Type Type;
85                 
86                 bool resolve_error;
87
88                 readonly bool nameEscaped;
89
90                 static AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
91                 static Assembly orig_sec_assembly;
92
93                 // non-null if named args present after Resolve () is called
94                 PropertyInfo [] prop_info_arr;
95                 FieldInfo [] field_info_arr;
96                 object [] field_values_arr;
97                 object [] prop_values_arr;
98                 object [] pos_values;
99
100                 static PtrHashtable usage_attr_cache = new PtrHashtable ();
101                 
102                 public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped)
103                 {
104                         LeftExpr = left_expr;
105                         Identifier = identifier;
106                         Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier;
107                         Arguments = args;
108                         Location = loc;
109                         ExplicitTarget = target;
110                         this.nameEscaped = nameEscaped;
111                 }
112
113                 void Error_InvalidNamedArgument (string name)
114                 {
115                         Report.Error (617, Location, "`{0}' is not a valid named attribute argument. Named attribute arguments must be fields which are not readonly, static, const or read-write properties which are public and not static",
116                               name);
117                 }
118
119                 void Error_InvalidNamedAgrumentType (string name)
120                 {
121                         Report.Error (655, Location, "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type", name);
122                 }
123
124                 static void Error_AttributeArgumentNotValid (string extra, Location loc)
125                 {
126                         Report.Error (182, loc,
127                                       "An attribute argument must be a constant expression, typeof " +
128                                       "expression or array creation expression" + extra);
129                 }
130
131                 static void Error_AttributeArgumentNotValid (Location loc)
132                 {
133                         Error_AttributeArgumentNotValid ("", loc);
134                 }
135                 
136                 static void Error_TypeParameterInAttribute (Location loc)
137                 {
138                         Report.Error (
139                                 -202, loc, "Can not use a type parameter in an attribute");
140                 }
141
142                 /// <summary>
143                 /// This is rather hack. We report many emit attribute error with same error to be compatible with
144                 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
145                 /// </summary>
146                 public void Error_AttributeEmitError (string inner)
147                 {
148                         Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'", TypeManager.CSharpName (Type), inner);
149                 }
150
151                 public void Error_InvalidSecurityParent ()
152                 {
153                         Error_AttributeEmitError ("it is attached to invalid parent");
154                 }
155
156                 protected virtual FullNamedExpression ResolveAsTypeTerminal (Expression expr, EmitContext ec, bool silent)
157                 {
158                         return expr.ResolveAsTypeTerminal (ec, silent);
159                 }
160
161                 protected virtual FullNamedExpression ResolveAsTypeStep (Expression expr, EmitContext ec, bool silent)
162                 {
163                         return expr.ResolveAsTypeStep (ec, silent);
164                 }
165
166                 Type ResolvePossibleAttributeType (EmitContext ec, string name, bool silent, ref bool is_attr)
167                 {
168                         FullNamedExpression fn;
169                         if (LeftExpr == null) {
170                                 fn = ResolveAsTypeTerminal (new SimpleName (name, Location), ec, silent);
171                         } else {
172                                 fn = ResolveAsTypeStep (LeftExpr, ec, silent);
173                                 if (fn == null)
174                                         return null;
175                                 fn = new MemberAccess (fn, name, Location).ResolveAsTypeTerminal (ec, silent);
176                         }
177
178                         TypeExpr te = fn as TypeExpr;
179                         if (te == null)
180                                 return null;
181
182                         Type t = te.Type;
183                         if (t.IsSubclassOf (TypeManager.attribute_type)) {
184                                 is_attr = true;
185                         } else if (!silent) {
186                                 Report.SymbolRelatedToPreviousError (t);
187                                 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
188                         }
189                         return t;
190                 }
191
192                 /// <summary>
193                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
194                 /// </summary>
195                 void ResolveAttributeType (EmitContext ec)
196                 {
197                         bool t1_is_attr = false;
198                         Type t1 = ResolvePossibleAttributeType (ec, Identifier, true, ref t1_is_attr);
199                         bool t2_is_attr = false;
200                         Type t2 = nameEscaped ? null :
201                                 ResolvePossibleAttributeType (ec, Identifier + "Attribute", true, ref t2_is_attr);
202
203                         if (t1_is_attr && t2_is_attr) {
204                                 Report.Error (1614, Location, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
205                                 resolve_error = true;
206                                 return;
207                         }
208                         if (t1_is_attr) {
209                                 Type = t1;
210                                 return;
211                         }
212
213                         if (t2_is_attr) {
214                                 Type = t2;
215                                 return;
216                         }
217
218                         if (t1 == null && t2 == null)
219                                 ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr);
220                         if (t1 != null)
221                                 ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr);
222                         if (t2 != null)
223                                 ResolvePossibleAttributeType (ec, Identifier + "Attribute", false, ref t2_is_attr);
224                         resolve_error = true;
225                 }
226
227                 public virtual Type ResolveType (EmitContext ec)
228                 {
229                         if (Type == null && !resolve_error)
230                                 ResolveAttributeType (ec);
231                         return Type;
232                 }
233
234                 public string GetSignatureForError ()
235                 {
236                         return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier;
237                 }
238
239                 //
240                 // Given an expression, if the expression is a valid attribute-argument-expression
241                 // returns an object that can be used to encode it, or null on failure.
242                 //
243                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result)
244                 {
245                         Constant constant = e as Constant;
246                         if (constant != null) {
247                                 constant = constant.ToType (arg_type, loc);
248                                 if (constant == null) {
249                                         result = null;
250                                         return false;
251                                 }
252                                 result = constant.GetTypedValue ();
253                                 return true;
254                         } else if (e is TypeOf) {
255                                 result = ((TypeOf) e).TypeArg;
256                                 return true;
257                         } else if (e is ArrayCreation){
258                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();
259                                 if (result != null)
260                                         return true;
261                         } else if (e is EmptyCast) {
262                                 Expression child = ((EmptyCast)e).Child;
263                                 return GetAttributeArgumentExpression (child, loc, child.Type, out result);
264                         } else if (e is As) {
265                                 As as_e = (As) e;
266                                 return GetAttributeArgumentExpression (as_e.Expr, loc, as_e.ProbeType.Type, out result);
267                         }
268
269                         result = null;
270                         Error_AttributeArgumentNotValid (loc);
271                         return false;
272                 }
273
274                 bool IsValidArgumentType (Type t)
275                 {
276                         if (t.IsArray)
277                                 t = t.GetElementType ();
278
279                         return TypeManager.IsPrimitiveType (t) ||
280                                 TypeManager.IsEnumType (t) ||
281                                 t == TypeManager.string_type ||
282                                 t == TypeManager.object_type ||
283                                 t == TypeManager.type_type;
284                 }
285
286                 // Cache for parameter-less attributes
287                 static PtrHashtable att_cache = new PtrHashtable ();
288
289                 public CustomAttributeBuilder Resolve (EmitContext ec)
290                 {
291                         if (resolve_error)
292                                 return null;
293
294                         resolve_error = true;
295
296                         if (Type == null) {
297                                 ResolveAttributeType (ec);
298                                 if (Type == null)
299                                         return null;
300                         }
301
302                         if (Type.IsAbstract) {
303                                 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
304                                 return null;
305                         }
306
307                         ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (Type);
308                         if (obsolete_attr != null) {
309                                 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location);
310                         }
311
312                         if (Arguments == null) {
313                                 object o = att_cache [Type];
314                                 if (o != null) {
315                                         resolve_error = false;
316                                         return (CustomAttributeBuilder)o;
317                                 }
318                         }
319
320                         ConstructorInfo ctor = ResolveArguments (ec);
321                         if (ctor == null) {
322                                 if (Type is TypeBuilder && 
323                                     TypeManager.LookupDeclSpace (Type).MemberCache == null)
324                                         // The attribute type has been DefineType'd, but not Defined.  Let's not treat it as an error.
325                                         // It'll be resolved again when the attached-to entity is emitted.
326                                         resolve_error = false;
327                                 return null;
328                         }
329
330                         CustomAttributeBuilder cb;
331
332                         try {
333                                 if (prop_info_arr != null || field_info_arr != null) {
334                                         cb = new CustomAttributeBuilder (
335                                                 ctor, pos_values,
336                                                 prop_info_arr, prop_values_arr,
337                                                 field_info_arr, field_values_arr);
338                                 } else {
339                                         cb = new CustomAttributeBuilder (
340                                                 ctor, pos_values);
341
342                                         if (pos_values.Length == 0)
343                                                 att_cache.Add (Type, cb);
344                                 }
345                         }
346                         catch (Exception) {
347                                 Error_AttributeArgumentNotValid (Location);
348                                 return null;
349                         }
350
351                         resolve_error = false;
352                         return cb;
353                 }
354
355                 protected virtual ConstructorInfo ResolveArguments (EmitContext ec)
356                 {
357                         // Now we extract the positional and named arguments
358                         
359                         ArrayList pos_args = null;
360                         ArrayList named_args = null;
361                         int pos_arg_count = 0;
362                         int named_arg_count = 0;
363                         
364                         if (Arguments != null) {
365                                 pos_args = (ArrayList) Arguments [0];
366                                 if (pos_args != null)
367                                         pos_arg_count = pos_args.Count;
368                                 if (Arguments.Count > 1) {
369                                         named_args = (ArrayList) Arguments [1];
370                                         named_arg_count = named_args.Count;
371                                 }
372                         }
373
374                         pos_values = new object [pos_arg_count];
375
376                         //
377                         // First process positional arguments 
378                         //
379
380                         int i;
381                         for (i = 0; i < pos_arg_count; i++) {
382                                 Argument a = (Argument) pos_args [i];
383                                 Expression e;
384
385                                 if (!a.Resolve (ec, Location))
386                                         return null;
387
388                                 e = a.Expr;
389
390                                 object val;
391                                 if (!GetAttributeArgumentExpression (e, Location, a.Type, out val))
392                                         return null;
393                                 
394                                 pos_values [i] = val;
395
396                                 if (i == 0 && Type == TypeManager.attribute_usage_type && (int)val == 0) {
397                                         Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute");
398                                         return null;
399                                 }
400                         }
401
402                         //
403                         // Now process named arguments
404                         //
405
406                         ArrayList field_infos = null;
407                         ArrayList prop_infos  = null;
408                         ArrayList field_values = null;
409                         ArrayList prop_values = null;
410                         Hashtable seen_names = null;
411
412                         if (named_arg_count > 0) {
413                                 field_infos = new ArrayList ();
414                                 prop_infos  = new ArrayList ();
415                                 field_values = new ArrayList ();
416                                 prop_values = new ArrayList ();
417
418                                 seen_names = new Hashtable();
419                         }
420                         
421                         for (i = 0; i < named_arg_count; i++) {
422                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
423                                 string member_name = (string) de.Key;
424                                 Argument a  = (Argument) de.Value;
425                                 Expression e;
426
427                                 if (seen_names.Contains(member_name)) {
428                                         Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument");
429                                         return null;
430                                 }                               
431                                 seen_names.Add(member_name, 1);
432                                 
433                                 if (!a.Resolve (ec, Location))
434                                         return null;
435
436                                 Expression member = Expression.MemberLookup (
437                                         ec, Type, member_name,
438                                         MemberTypes.Field | MemberTypes.Property,
439                                         BindingFlags.Public | BindingFlags.Instance,
440                                         Location);
441
442                                 if (member == null) {
443                                         member = Expression.MemberLookup (ec, Type, member_name,
444                                                 MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance,
445                                                 Location);
446
447                                         if (member != null) {
448                                                 Expression.ErrorIsInaccesible (Location, member.GetSignatureForError ());
449                                                 return null;
450                                         }
451                                 }
452
453                                 if (member == null){
454                                         Report.Error (117, Location, "`{0}' does not contain a definition for `{1}'",
455                                                       Type, member_name);
456                                         return null;
457                                 }
458                                 
459                                 if (!(member is PropertyExpr || member is FieldExpr)) {
460                                         Error_InvalidNamedArgument (member_name);
461                                         return null;
462                                 }
463
464                                 e = a.Expr;
465                                 if (e is TypeParameterExpr){
466                                         Error_TypeParameterInAttribute (Location);
467                                         return null;
468                                 }
469                                         
470                                 if (member is PropertyExpr) {
471                                         PropertyExpr pe = (PropertyExpr) member;
472                                         PropertyInfo pi = pe.PropertyInfo;
473
474                                         if (!pi.CanWrite || !pi.CanRead) {
475                                                 Report.SymbolRelatedToPreviousError (pi);
476                                                 Error_InvalidNamedArgument (member_name);
477                                                 return null;
478                                         }
479
480                                         if (!IsValidArgumentType (pi.PropertyType)) {
481                                                 Report.SymbolRelatedToPreviousError (pi);
482                                                 Error_InvalidNamedAgrumentType (member_name);
483                                                 return null;
484                                         }
485
486                                         object value;
487                                         if (!GetAttributeArgumentExpression (e, Location, pi.PropertyType, out value))
488                                                 return null;
489
490                                         prop_values.Add (value);
491                                         prop_infos.Add (pi);
492                                         
493                                 } else if (member is FieldExpr) {
494                                         FieldExpr fe = (FieldExpr) member;
495                                         FieldInfo fi = fe.FieldInfo;
496
497                                         if (fi.IsInitOnly) {
498                                                 Error_InvalidNamedArgument (member_name);
499                                                 return null;
500                                         }
501
502                                         if (!IsValidArgumentType (fi.FieldType)) {
503                                                 Report.SymbolRelatedToPreviousError (fi);
504                                                 Error_InvalidNamedAgrumentType (member_name);
505                                                 return null;
506                                         }
507
508                                         object value;
509                                         if (!GetAttributeArgumentExpression (e, Location, fi.FieldType, out value))
510                                                 return null;
511
512                                         field_values.Add (value);
513
514                                         field_infos.Add (fi);
515                                 }
516                         }
517
518                         Expression mg = Expression.MemberLookup (
519                                 ec, Type, ".ctor", MemberTypes.Constructor,
520                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
521                                 Location);
522
523                         if (mg == null) {
524                                 // FIXME: Punt the issue for now.
525                                 if (Type is TypeBuilder)
526                                         return null;
527                                 throw new InternalErrorException ("Type " + Type + " doesn't have constructors");
528                         }
529
530                         MethodBase constructor = Invocation.OverloadResolve (
531                                 ec, (MethodGroupExpr) mg, pos_args, false, Location);
532
533                         if (constructor == null) {
534                                 return null;
535                         }
536
537
538                         // Here we do the checks which should be done by corlib or by runtime.
539                         // However Zoltan doesn't like it and every Mono compiler has to do it again.
540                         
541                         if (Type == TypeManager.guid_attr_type) {
542                                 try {
543                                         new Guid ((string)pos_values [0]);
544                                 }
545                                 catch (Exception e) {
546                                         Error_AttributeEmitError (e.Message);
547                                         return null;
548                                 }
549                         }
550
551                         if (Type == TypeManager.methodimpl_attr_type &&
552                                 pos_values.Length == 1 && ((Argument)pos_args [0]).Type == TypeManager.short_type &&
553                                 !System.Enum.IsDefined (typeof (MethodImplOptions), pos_values [0])) {
554                                         Error_AttributeEmitError ("Incorrect argument value.");
555                                 return null;
556                         }
557
558                         //
559                         // Now we perform some checks on the positional args as they
560                         // cannot be null for a constructor which expects a parameter
561                         // of type object
562                         //
563
564                         ParameterData pd = TypeManager.GetParameterData (constructor);
565
566                         int last_real_param = pd.Count;
567                         if (pd.HasParams) {
568                                 // When the params is not filled we need to put one
569                                 if (last_real_param > pos_arg_count) {
570                                         object [] new_pos_values = new object [pos_arg_count + 1];
571                                         pos_values.CopyTo (new_pos_values, 0);
572                                         new_pos_values [pos_arg_count] = new object [] {} ;
573                                         pos_values = new_pos_values;
574                                 }
575                                 last_real_param--;
576                         }
577
578                         for (int j = 0; j < pos_arg_count; ++j) {
579                                 Argument a = (Argument) pos_args [j];
580                                 
581                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
582                                         Error_AttributeArgumentNotValid (Location);
583                                         return null;
584                                 }
585
586                                 object value = pos_values [j];
587                                 if (value != null && a.Type != value.GetType () && TypeManager.IsPrimitiveType (a.Type)) {
588                                         bool fail;
589                                         pos_values [j] = TypeManager.ChangeType (value, a.Type, out fail);
590                                         if (fail) {
591                                                 // TODO: Can failed ?
592                                                 throw new NotImplementedException ();
593                                         }
594                                 }
595
596                                 if (j < last_real_param)
597                                         continue;
598                                 
599                                 if (j == last_real_param) {
600                                         object [] array = new object [pos_arg_count - last_real_param];
601                                         array [0] = pos_values [j];
602                                         pos_values [j] = array;
603                                         continue;
604                                 }
605
606                                 object [] params_array = (object []) pos_values [last_real_param];
607                                 params_array [j - last_real_param] = pos_values [j];
608                         }
609
610                         // Adjust the size of the pos_values if it had params
611                         if (last_real_param != pos_arg_count) {
612                                 object [] new_pos_values = new object [last_real_param + 1];
613                                 Array.Copy (pos_values, new_pos_values, last_real_param + 1);
614                                 pos_values = new_pos_values;
615                         }
616
617                         if (named_arg_count > 0) {
618                                 prop_info_arr = new PropertyInfo [prop_infos.Count];
619                                 field_info_arr = new FieldInfo [field_infos.Count];
620                                 field_values_arr = new object [field_values.Count];
621                                 prop_values_arr = new object [prop_values.Count];
622
623                                 field_infos.CopyTo  (field_info_arr, 0);
624                                 field_values.CopyTo (field_values_arr, 0);
625
626                                 prop_values.CopyTo  (prop_values_arr, 0);
627                                 prop_infos.CopyTo   (prop_info_arr, 0);
628                         }
629
630                         return (ConstructorInfo) constructor;
631                 }
632
633                 /// <summary>
634                 ///   Get a string containing a list of valid targets for the attribute 'attr'
635                 /// </summary>
636                 public string GetValidTargets ()
637                 {
638                         StringBuilder sb = new StringBuilder ();
639                         AttributeTargets targets = GetAttributeUsage (null).ValidOn;
640
641                         if ((targets & AttributeTargets.Assembly) != 0)
642                                 sb.Append ("assembly, ");
643
644                         if ((targets & AttributeTargets.Module) != 0)
645                                 sb.Append ("module, ");
646
647                         if ((targets & AttributeTargets.Class) != 0)
648                                 sb.Append ("class, ");
649
650                         if ((targets & AttributeTargets.Struct) != 0)
651                                 sb.Append ("struct, ");
652
653                         if ((targets & AttributeTargets.Enum) != 0)
654                                 sb.Append ("enum, ");
655
656                         if ((targets & AttributeTargets.Constructor) != 0)
657                                 sb.Append ("constructor, ");
658
659                         if ((targets & AttributeTargets.Method) != 0)
660                                 sb.Append ("method, ");
661
662                         if ((targets & AttributeTargets.Property) != 0)
663                                 sb.Append ("property, indexer, ");
664
665                         if ((targets & AttributeTargets.Field) != 0)
666                                 sb.Append ("field, ");
667
668                         if ((targets & AttributeTargets.Event) != 0)
669                                 sb.Append ("event, ");
670
671                         if ((targets & AttributeTargets.Interface) != 0)
672                                 sb.Append ("interface, ");
673
674                         if ((targets & AttributeTargets.Parameter) != 0)
675                                 sb.Append ("parameter, ");
676
677                         if ((targets & AttributeTargets.Delegate) != 0)
678                                 sb.Append ("delegate, ");
679
680                         if ((targets & AttributeTargets.ReturnValue) != 0)
681                                 sb.Append ("return, ");
682
683                         if ((targets & AttributeTargets.GenericParameter) != 0)
684                                 sb.Append ("type parameter, ");
685                         return sb.Remove (sb.Length - 2, 2).ToString ();
686                 }
687
688                 /// <summary>
689                 /// Returns AttributeUsage attribute for this type
690                 /// </summary>
691                 AttributeUsageAttribute GetAttributeUsage (EmitContext ec)
692                 {
693                         AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute;
694                         if (ua != null)
695                                 return ua;
696
697                         Class attr_class = TypeManager.LookupClass (Type);
698
699                         if (attr_class == null) {
700                                 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
701                                 ua = (AttributeUsageAttribute)usage_attr [0];
702                                 usage_attr_cache.Add (Type, ua);
703                                 return ua;
704                         }
705
706                         Attribute a = attr_class.OptAttributes == null
707                                 ? null
708                                 : attr_class.OptAttributes.Search (TypeManager.attribute_usage_type, attr_class.EmitContext);
709
710                         ua = a == null
711                                 ? DefaultUsageAttribute 
712                                 : a.GetAttributeUsageAttribute (attr_class.EmitContext);
713
714                         usage_attr_cache.Add (Type, ua);
715                         return ua;
716                 }
717
718                 AttributeUsageAttribute GetAttributeUsageAttribute (EmitContext ec)
719                 {
720                         if (pos_values == null)
721                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
722                                 // But because a lot of attribute class code must be rewritten will be better to wait...
723                                 Resolve (ec);
724
725                         if (resolve_error)
726                                 return DefaultUsageAttribute;
727
728                         AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)pos_values [0]);
729
730                         object field = GetPropertyValue ("AllowMultiple");
731                         if (field != null)
732                                 usage_attribute.AllowMultiple = (bool)field;
733
734                         field = GetPropertyValue ("Inherited");
735                         if (field != null)
736                                 usage_attribute.Inherited = (bool)field;
737
738                         return usage_attribute;
739                 }
740
741                 /// <summary>
742                 /// Returns custom name of indexer
743                 /// </summary>
744                 public string GetIndexerAttributeValue (EmitContext ec)
745                 {
746                         if (pos_values == null)
747                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
748                                 // But because a lot of attribute class code must be rewritten will be better to wait...
749                                 Resolve (ec);
750                         
751                         if (resolve_error)
752                                 return null;
753
754                         return pos_values [0] as string;
755                 }
756
757                 /// <summary>
758                 /// Returns condition of ConditionalAttribute
759                 /// </summary>
760                 public string GetConditionalAttributeValue (EmitContext ec)
761                 {
762                         if (pos_values == null)
763                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
764                                 // But because a lot of attribute class code must be rewritten will be better to wait...
765                                 Resolve (ec);
766
767                         if (resolve_error)
768                                 return null;
769
770                         return (string)pos_values [0];
771                 }
772
773                 /// <summary>
774                 /// Creates the instance of ObsoleteAttribute from this attribute instance
775                 /// </summary>
776                 public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec)
777                 {
778                         if (pos_values == null)
779                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
780                                 // But because a lot of attribute class code must be rewritten will be better to wait...
781                                 Resolve (ec);
782
783                         if (resolve_error)
784                                 return null;
785
786                         if (pos_values == null || pos_values.Length == 0)
787                                 return new ObsoleteAttribute ();
788
789                         if (pos_values.Length == 1)
790                                 return new ObsoleteAttribute ((string)pos_values [0]);
791
792                         return new ObsoleteAttribute ((string)pos_values [0], (bool)pos_values [1]);
793                 }
794
795                 /// <summary>
796                 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
797                 /// before ApplyAttribute. We need to resolve the arguments.
798                 /// This situation occurs when class deps is differs from Emit order.  
799                 /// </summary>
800                 public bool GetClsCompliantAttributeValue (EmitContext ec)
801                 {
802                         if (pos_values == null)
803                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
804                                 // But because a lot of attribute class code must be rewritten will be better to wait...
805                                 Resolve (ec);
806
807                         if (resolve_error)
808                                 return false;
809
810                         return (bool)pos_values [0];
811                 }
812
813                 /// <summary>
814                 /// Tests permitted SecurityAction for assembly or other types
815                 /// </summary>
816                 public bool CheckSecurityActionValidity (bool for_assembly)
817                 {
818                         SecurityAction action = GetSecurityActionValue ();
819
820                         switch (action) {
821                         case SecurityAction.Demand:
822                         case SecurityAction.Assert:
823                         case SecurityAction.Deny:
824                         case SecurityAction.PermitOnly:
825                         case SecurityAction.LinkDemand:
826                         case SecurityAction.InheritanceDemand:
827                                 if (!for_assembly)
828                                         return true;
829                                 break;
830
831                         case SecurityAction.RequestMinimum:
832                         case SecurityAction.RequestOptional:
833                         case SecurityAction.RequestRefuse:
834                                 if (for_assembly)
835                                         return true;
836                                 break;
837
838                         default:
839                                 Error_AttributeEmitError ("SecurityAction is out of range X");
840                                 return false;
841                         }
842
843                         Error_AttributeEmitError (String.Concat ("SecurityAction '", action, "' is not valid for this declaration"));
844                         return false;
845                 }
846
847                 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
848                 {
849                         return (SecurityAction)pos_values [0];
850                 }
851
852                 /// <summary>
853                 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
854                 /// </summary>
855                 /// <returns></returns>
856                 public void ExtractSecurityPermissionSet (ListDictionary permissions)
857                 {
858                         Type orig_assembly_type = null;
859
860                         if (TypeManager.LookupDeclSpace (Type) != null) {
861                                 if (!RootContext.StdLib) {
862                                         orig_assembly_type = Type.GetType (Type.FullName);
863                                 } else {
864                                         string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
865                                         if (orig_version_path == null) {
866                                                 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
867                                                 return;
868                                         }
869
870                                         if (orig_sec_assembly == null) {
871                                                 string file = Path.Combine (orig_version_path, Driver.OutputFile);
872                                                 orig_sec_assembly = Assembly.LoadFile (file);
873                                         }
874
875                                         orig_assembly_type = orig_sec_assembly.GetType (Type.FullName, true);
876                                         if (orig_assembly_type == null) {
877                                                 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' was not found in previous version of assembly");
878                                                 return;
879                                         }
880                                 }
881                         }
882
883                         SecurityAttribute sa;
884                         // For all non-selfreferencing security attributes we can avoid all hacks
885                         if (orig_assembly_type == null) {
886                                 sa = (SecurityAttribute) Activator.CreateInstance (Type, pos_values);
887
888                                 if (prop_info_arr != null) {
889                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
890                                                 PropertyInfo pi = prop_info_arr [i];
891                                                 pi.SetValue (sa, prop_values_arr [i], null);
892                                         }
893                                 }
894                         } else {
895                                 // HACK: All security attributes have same ctor syntax
896                                 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, new object[] { GetSecurityActionValue () } );
897
898                                 // All types are from newly created assembly but for invocation with old one we need to convert them
899                                 if (prop_info_arr != null) {
900                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
901                                                 PropertyInfo emited_pi = prop_info_arr [i];
902                                                 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name, emited_pi.PropertyType);
903
904                                                 object old_instance = pi.PropertyType.IsEnum ?
905                                                         System.Enum.ToObject (pi.PropertyType, prop_values_arr [i]) :
906                                                         prop_values_arr [i];
907
908                                                 pi.SetValue (sa, old_instance, null);
909                                         }
910                                 }
911                         }
912
913                         IPermission perm;
914                         perm = sa.CreatePermission ();
915                         SecurityAction action = GetSecurityActionValue ();
916
917                         // IS is correct because for corlib we are using an instance from old corlib
918                         if (!(perm is System.Security.CodeAccessPermission)) {
919                                 switch (action) {
920                                         case SecurityAction.Demand:
921                                                 action = (SecurityAction)13;
922                                                 break;
923                                         case SecurityAction.LinkDemand:
924                                                 action = (SecurityAction)14;
925                                                 break;
926                                         case SecurityAction.InheritanceDemand:
927                                                 action = (SecurityAction)15;
928                                                 break;
929                                 }
930                         }
931
932                         PermissionSet ps = (PermissionSet)permissions [action];
933                         if (ps == null) {
934                                 if (sa is PermissionSetAttribute)
935                                         ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
936                                 else
937                                         ps = new PermissionSet (PermissionState.None);
938
939                                 permissions.Add (action, ps);
940                         } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
941                                 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
942                                 permissions [action] = ps;
943                         }
944                         ps.AddPermission (perm);
945                 }
946
947                 object GetValue (object value)
948                 {
949                         if (value is EnumConstant)
950                                 return ((EnumConstant) value).GetValue ();
951                         else
952                                 return value;                           
953                 }
954
955                 object GetPropertyValue (string name)
956                 {
957                         if (prop_info_arr == null)
958                                 return null;
959
960                         for (int i = 0; i < prop_info_arr.Length; ++i) {
961                                 if (prop_info_arr [i].Name == name)
962                                         return prop_values_arr [i];
963                         }
964
965                         return null;
966                 }
967
968                 object GetFieldValue (string name)
969                 {
970                         int i;
971                         if (field_info_arr == null)
972                                 return null;
973                         i = 0;
974                         foreach (FieldInfo fi in field_info_arr) {
975                                 if (fi.Name == name)
976                                         return GetValue (field_values_arr [i]);
977                                 i++;
978                         }
979                         return null;
980                 }
981
982                 //
983                 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
984                 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
985                 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
986                 //
987                 public UnmanagedMarshal GetMarshal (Attributable attr)
988                 {
989                         UnmanagedType UnmanagedType;
990                         if (!RootContext.StdLib || pos_values [0].GetType () != typeof (UnmanagedType))
991                                 UnmanagedType = (UnmanagedType) System.Enum.ToObject (typeof (UnmanagedType), pos_values [0]);
992                         else
993                                 UnmanagedType = (UnmanagedType) pos_values [0];
994
995                         object value = GetFieldValue ("SizeParamIndex");
996                         if (value != null && UnmanagedType != UnmanagedType.LPArray) {
997                                 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
998                                 return null;
999                         }
1000
1001                         object o = GetFieldValue ("ArraySubType");
1002                         UnmanagedType array_sub_type = o == null ? (UnmanagedType) 0x50 /* NATIVE_MAX */ : (UnmanagedType) o;
1003
1004                         switch (UnmanagedType) {
1005                         case UnmanagedType.CustomMarshaler: {
1006                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
1007                                         BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1008                                 if (define_custom == null) {
1009                                         Report.RuntimeMissingSupport (Location, "set marshal info");
1010                                         return null;
1011                                 }
1012                                 
1013                                 object [] args = new object [4];
1014                                 args [0] = GetFieldValue ("MarshalTypeRef");
1015                                 args [1] = GetFieldValue ("MarshalCookie");
1016                                 args [2] = GetFieldValue ("MarshalType");
1017                                 args [3] = Guid.Empty;
1018                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);
1019                         }
1020                         case UnmanagedType.LPArray: {
1021                                 object size_const = GetFieldValue ("SizeConst");
1022                                 object size_param_index = GetFieldValue ("SizeParamIndex");
1023
1024                                 if ((size_const != null) || (size_param_index != null)) {
1025                                         MethodInfo define_array = typeof (UnmanagedMarshal).GetMethod ("DefineLPArrayInternal",
1026                                                 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1027                                         if (define_array == null) {
1028                                                 Report.RuntimeMissingSupport (Location, "set marshal info");
1029                                                 return null;
1030                                         }
1031                                 
1032                                         object [] args = new object [3];
1033                                         args [0] = array_sub_type;
1034                                         args [1] = size_const == null ? -1 : size_const;
1035                                         args [2] = size_param_index == null ? -1 : size_param_index;
1036                                         return (UnmanagedMarshal) define_array.Invoke (null, args);
1037                                 }
1038                                 else
1039                                         return UnmanagedMarshal.DefineLPArray (array_sub_type);
1040                         }
1041                         case UnmanagedType.SafeArray:
1042                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
1043
1044                         case UnmanagedType.ByValArray:
1045                                 FieldMember fm = attr as FieldMember;
1046                                 if (fm == null) {
1047                                         Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1048                                         return null;
1049                                 }
1050                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1051
1052                         case UnmanagedType.ByValTStr:
1053                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1054
1055                         default:
1056                                 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
1057                         }
1058                 }
1059
1060                 public CharSet GetCharSetValue ()
1061                 {
1062                         return (CharSet)System.Enum.Parse (typeof (CharSet), pos_values [0].ToString ());
1063                 }
1064
1065                 public MethodImplOptions GetMethodImplOptions ()
1066                 {
1067                         if (pos_values [0].GetType () != typeof (MethodImplOptions))
1068                                 return (MethodImplOptions)System.Enum.ToObject (typeof (MethodImplOptions), pos_values [0]);
1069                         return (MethodImplOptions)pos_values [0];
1070                 }
1071
1072                 public LayoutKind GetLayoutKindValue ()
1073                 {
1074                         if (!RootContext.StdLib || pos_values [0].GetType () != typeof (LayoutKind))
1075                                 return (LayoutKind)System.Enum.ToObject (typeof (LayoutKind), pos_values [0]);
1076
1077                         return (LayoutKind)pos_values [0];
1078                 }
1079
1080                 /// <summary>
1081                 /// Emit attribute for Attributable symbol
1082                 /// </summary>
1083                 public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr)
1084                 {
1085                         CustomAttributeBuilder cb = Resolve (ec);
1086                         if (cb == null)
1087                                 return;
1088
1089                         AttributeUsageAttribute usage_attr = GetAttributeUsage (ec);
1090                         if ((usage_attr.ValidOn & Target) == 0) {
1091                                 Report.Error (592, Location, "Attribute `{0}' is not valid on this declaration type. It is valid on `{1}' declarations only",
1092                                         GetSignatureForError (), GetValidTargets ());
1093                                 return;
1094                         }
1095
1096                         try {
1097                                 ias.ApplyAttributeBuilder (this, cb);
1098                         }
1099                         catch (Exception e) {
1100                                 Error_AttributeEmitError (e.Message);
1101                                 return;
1102                         }
1103
1104                         if (!usage_attr.AllowMultiple) {
1105                                 ArrayList emitted_targets = (ArrayList)emitted_attr [Type];
1106                                 if (emitted_targets == null) {
1107                                         emitted_targets = new ArrayList ();
1108                                         emitted_attr.Add (Type, emitted_targets);
1109                                 } else if (emitted_targets.Contains (Target)) {
1110                                         Report.Error (579, Location, "Duplicate `{0}' attribute", GetSignatureForError ());
1111                                         return;
1112                                 }
1113                                 emitted_targets.Add (Target);
1114                         }
1115
1116                         if (!RootContext.VerifyClsCompliance)
1117                                 return;
1118
1119                         // Here we are testing attribute arguments for array usage (error 3016)
1120                         if (ias.IsClsComplianceRequired (ec.DeclSpace)) {
1121                                 if (Arguments == null)
1122                                         return;
1123
1124                                 ArrayList pos_args = (ArrayList) Arguments [0];
1125                                 if (pos_args != null) {
1126                                         foreach (Argument arg in pos_args) { 
1127                                                 // Type is undefined (was error 246)
1128                                                 if (arg.Type == null)
1129                                                         return;
1130
1131                                                 if (arg.Type.IsArray) {
1132                                                         Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
1133                                                         return;
1134                                                 }
1135                                         }
1136                                 }
1137                         
1138                                 if (Arguments.Count < 2)
1139                                         return;
1140                         
1141                                 ArrayList named_args = (ArrayList) Arguments [1];
1142                                 foreach (DictionaryEntry de in named_args) {
1143                                         Argument arg  = (Argument) de.Value;
1144
1145                                         // Type is undefined (was error 246)
1146                                         if (arg.Type == null)
1147                                                 return;
1148
1149                                         if (arg.Type.IsArray) {
1150                                                 Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
1151                                                 return;
1152                                         }
1153                                 }
1154                         }
1155                 }
1156                 
1157                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
1158                                                           MethodAttributes flags, Type ret_type, Type [] param_types)
1159                 {
1160                         if (pos_values == null)
1161                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
1162                                 // But because a lot of attribute class code must be rewritten will be better to wait...
1163                                 Resolve (ec);
1164
1165                         if (resolve_error)
1166                                 return null;
1167                         
1168                         string dll_name = (string)pos_values [0];
1169
1170                         // Default settings
1171                         CallingConvention cc = CallingConvention.Winapi;
1172                         CharSet charset = CodeGen.Module.DefaultCharSet;
1173                         bool preserve_sig = true;
1174                         string entry_point = name;
1175                         bool best_fit_mapping = false;
1176                         bool throw_on_unmappable = false;
1177                         bool exact_spelling = false;
1178                         bool set_last_error = false;
1179
1180                         bool best_fit_mapping_set = false;
1181                         bool throw_on_unmappable_set = false;
1182                         bool exact_spelling_set = false;
1183                         bool set_last_error_set = false;
1184
1185                         MethodInfo set_best_fit = null;
1186                         MethodInfo set_throw_on = null;
1187                         MethodInfo set_exact_spelling = null;
1188                         MethodInfo set_set_last_error = null;
1189
1190                         if (field_info_arr != null) {
1191
1192                                 for (int i = 0; i < field_info_arr.Length; i++) {
1193                                         switch (field_info_arr [i].Name) {
1194                                                 case "BestFitMapping":
1195                                                         best_fit_mapping = (bool) field_values_arr [i];
1196                                                         best_fit_mapping_set = true;
1197                                                         break;
1198                                                 case "CallingConvention":
1199                                                         cc = (CallingConvention) field_values_arr [i];
1200                                                         break;
1201                                                 case "CharSet":
1202                                                         charset = (CharSet) field_values_arr [i];
1203                                                         break;
1204                                                 case "EntryPoint":
1205                                                         entry_point = (string) field_values_arr [i];
1206                                                         break;
1207                                                 case "ExactSpelling":
1208                                                         exact_spelling = (bool) field_values_arr [i];
1209                                                         exact_spelling_set = true;
1210                                                         break;
1211                                                 case "PreserveSig":
1212                                                         preserve_sig = (bool) field_values_arr [i];
1213                                                         break;
1214                                                 case "SetLastError":
1215                                                         set_last_error = (bool) field_values_arr [i];
1216                                                         set_last_error_set = true;
1217                                                         break;
1218                                                 case "ThrowOnUnmappableChar":
1219                                                         throw_on_unmappable = (bool) field_values_arr [i];
1220                                                         throw_on_unmappable_set = true;
1221                                                         break;
1222                                                 default: 
1223                                                         throw new InternalErrorException (field_info_arr [i].ToString ());
1224                                         }
1225                                 }
1226                         }
1227
1228                         if (throw_on_unmappable_set || best_fit_mapping_set || exact_spelling_set || set_last_error_set) {
1229                                 set_best_fit = typeof (MethodBuilder).GetMethod ("set_BestFitMapping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1230                                 set_throw_on = typeof (MethodBuilder).GetMethod ("set_ThrowOnUnmappableChar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1231                                 set_exact_spelling = typeof (MethodBuilder).GetMethod ("set_ExactSpelling", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1232                                 set_set_last_error = typeof (MethodBuilder).GetMethod ("set_SetLastError", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1233
1234                                 if ((set_best_fit == null) || (set_throw_on == null) || (set_exact_spelling == null) || (set_set_last_error == null)) {
1235                                         Report.Error (-1, Location,
1236                                                                   "The ThrowOnUnmappableChar, BestFitMapping, SetLastError, and ExactSpelling attributes can only be emitted when running on the mono runtime.");
1237                                         return null;
1238                                 }
1239                         }
1240
1241                         try {
1242                                 MethodBuilder mb = builder.DefinePInvokeMethod (
1243                                         name, dll_name, entry_point, flags | MethodAttributes.HideBySig | MethodAttributes.PinvokeImpl,
1244                                         CallingConventions.Standard, ret_type, param_types, cc, charset);
1245
1246                                 if (preserve_sig)
1247                                         mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
1248
1249                                 if (throw_on_unmappable_set)
1250                                         set_throw_on.Invoke (mb, 0, null, new object [] { throw_on_unmappable }, null);
1251                                 if (best_fit_mapping_set)
1252                                         set_best_fit.Invoke (mb, 0, null, new object [] { best_fit_mapping }, null);
1253                                 if (exact_spelling_set)
1254                                         set_exact_spelling.Invoke  (mb, 0, null, new object [] { exact_spelling }, null);
1255                                 if (set_last_error_set)
1256                                         set_set_last_error.Invoke  (mb, 0, null, new object [] { set_last_error }, null);
1257                         
1258                                 return mb;
1259                         }
1260                         catch (ArgumentException e) {
1261                                 Error_AttributeEmitError (e.Message);
1262                                 return null;
1263                         }
1264                 }
1265
1266                 private Expression GetValue () 
1267                 {
1268                         if ((Arguments == null) || (Arguments.Count < 1))
1269                                 return null;
1270                         ArrayList al = (ArrayList) Arguments [0];
1271                         if ((al == null) || (al.Count < 1))
1272                                 return null;
1273                         Argument arg = (Argument) al [0];
1274                         if ((arg == null) || (arg.Expr == null))
1275                                 return null;
1276                         return arg.Expr;
1277                 }
1278
1279                 public string GetString () 
1280                 {
1281                         Expression e = GetValue ();
1282                         if (e is StringLiteral)
1283                                 return (e as StringLiteral).Value;
1284                         return null;
1285                 }
1286
1287                 public bool GetBoolean () 
1288                 {
1289                         Expression e = GetValue ();
1290                         if (e is BoolLiteral)
1291                                 return (e as BoolLiteral).Value;
1292                         return false;
1293                 }
1294         }
1295         
1296
1297         /// <summary>
1298         /// For global attributes (assembly, module) we need special handling.
1299         /// Attributes can be located in the several files
1300         /// </summary>
1301         public class GlobalAttribute: Attribute
1302         {
1303                 public readonly NamespaceEntry ns;
1304
1305                 public GlobalAttribute (TypeContainer container, string target, 
1306                                         Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped):
1307                         base (target, left_expr, identifier, args, loc, nameEscaped)
1308                 {
1309                         ns = container.NamespaceEntry;
1310                 }
1311
1312                 void Enter ()
1313                 {
1314                         // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
1315                         // each time a new file is parsed.  However, we need to use the NamespaceEntry
1316                         // in effect where the attribute was used.  Since code elsewhere cannot assume
1317                         // that the NamespaceEntry is right, just overwrite it.
1318                         //
1319                         // Precondition: RootContext.Tree.Types == null
1320
1321                         if (RootContext.Tree.Types.NamespaceEntry != null)
1322                                 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1323
1324                         RootContext.Tree.Types.NamespaceEntry = ns;
1325                 }
1326
1327                 void Leave ()
1328                 {
1329                         RootContext.Tree.Types.NamespaceEntry = null;
1330                 }
1331
1332                 protected override FullNamedExpression ResolveAsTypeStep (Expression expr, EmitContext ec, bool silent)
1333                 {
1334                         try {
1335                                 Enter ();
1336                                 return base.ResolveAsTypeStep (expr, ec, silent);
1337                         }
1338                         finally {
1339                                 Leave ();
1340                         }
1341                 }
1342
1343
1344                 protected override FullNamedExpression ResolveAsTypeTerminal (Expression expr, EmitContext ec, bool silent)
1345                 {
1346                         try {
1347                                 Enter ();
1348                                 return base.ResolveAsTypeTerminal (expr, ec, silent);
1349                         }
1350                         finally {
1351                                 Leave ();
1352                         }
1353                 }
1354
1355                 protected override ConstructorInfo ResolveArguments (EmitContext ec)
1356                 {
1357                         try {
1358                                 Enter ();
1359                                 return base.ResolveArguments (ec);
1360                         }
1361                         finally {
1362                                 Leave ();
1363                         }
1364                 }
1365         }
1366
1367         public class Attributes {
1368                 public ArrayList Attrs;
1369
1370                 public Attributes (Attribute a)
1371                 {
1372                         Attrs = new ArrayList ();
1373                         Attrs.Add (a);
1374                 }
1375
1376                 public Attributes (ArrayList attrs)
1377                 {
1378                         Attrs = attrs;
1379                 }
1380
1381                 public void AddAttributes (ArrayList attrs)
1382                 {
1383                         Attrs.AddRange (attrs);
1384                 }
1385
1386                 /// <summary>
1387                 /// Checks whether attribute target is valid for the current element
1388                 /// </summary>
1389                 public bool CheckTargets (Attributable member)
1390                 {
1391                         string[] valid_targets = member.ValidAttributeTargets;
1392                         foreach (Attribute a in Attrs) {
1393                                 if (a.ExplicitTarget == null || a.ExplicitTarget == valid_targets [0]) {
1394                                         a.Target = member.AttributeTargets;
1395                                         continue;
1396                                 }
1397
1398                                 // TODO: we can skip the first item
1399                                 if (((IList) valid_targets).Contains (a.ExplicitTarget)) {
1400                                         switch (a.ExplicitTarget) {
1401                                                 case "return": a.Target = AttributeTargets.ReturnValue; continue;
1402                                                 case "param": a.Target = AttributeTargets.Parameter; continue;
1403                                                 case "field": a.Target = AttributeTargets.Field; continue;
1404                                                 case "method": a.Target = AttributeTargets.Method; continue;
1405                                                 case "property": a.Target = AttributeTargets.Property; continue;
1406                                         }
1407                                         throw new InternalErrorException ("Unknown explicit target: " + a.ExplicitTarget);
1408                                 }
1409
1410                                 StringBuilder sb = new StringBuilder ();
1411                                 foreach (string s in valid_targets) {
1412                                         sb.Append (s);
1413                                         sb.Append (", ");
1414                                 }
1415                                 sb.Remove (sb.Length - 2, 2);
1416                                 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 ());
1417                                 return false;
1418                         }
1419                         return true;
1420                 }
1421
1422                 public Attribute Search (Type t, EmitContext ec)
1423                 {
1424                         foreach (Attribute a in Attrs) {
1425                                 if (a.ResolveType (ec) == t)
1426                                         return a;
1427                         }
1428                         return null;
1429                 }
1430
1431                 /// <summary>
1432                 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1433                 /// </summary>
1434                 public Attribute[] SearchMulti (Type t, EmitContext ec)
1435                 {
1436                         ArrayList ar = null;
1437
1438                         foreach (Attribute a in Attrs) {
1439                                 if (a.ResolveType (ec) == t) {
1440                                         if (ar == null)
1441                                                 ar = new ArrayList ();
1442                                         ar.Add (a);
1443                                 }
1444                         }
1445
1446                         return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
1447                 }
1448
1449                 public void Emit (EmitContext ec, Attributable ias)
1450                 {
1451                         CheckTargets (ias);
1452
1453                         ListDictionary ld = new ListDictionary ();
1454
1455                         foreach (Attribute a in Attrs)
1456                                 a.Emit (ec, ias, ld);
1457                 }
1458
1459                 public bool Contains (Type t, EmitContext ec)
1460                 {
1461                         return Search (t, ec) != null;
1462                 }
1463         }
1464
1465         /// <summary>
1466         /// Helper class for attribute verification routine.
1467         /// </summary>
1468         sealed class AttributeTester
1469         {
1470                 static PtrHashtable analyzed_types = new PtrHashtable ();
1471                 static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
1472                 static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
1473                 static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
1474
1475                 static PtrHashtable fixed_buffer_cache = new PtrHashtable ();
1476
1477                 static object TRUE = new object ();
1478                 static object FALSE = new object ();
1479
1480                 private AttributeTester ()
1481                 {
1482                 }
1483
1484                 public enum Result {
1485                         Ok,
1486                         RefOutArrayError,
1487                         ArrayArrayError
1488                 }
1489
1490                 /// <summary>
1491                 /// Returns true if parameters of two compared methods are CLS-Compliant.
1492                 /// It tests differing only in ref or out, or in array rank.
1493                 /// </summary>
1494                 public static Result AreOverloadedMethodParamsClsCompliant (Type[] types_a, Type[] types_b) 
1495                 {
1496                         if (types_a == null || types_b == null)
1497                                 return Result.Ok;
1498
1499                         if (types_a.Length != types_b.Length)
1500                                 return Result.Ok;
1501
1502                         Result result = Result.Ok;
1503                         for (int i = 0; i < types_b.Length; ++i) {
1504                                 Type aType = types_a [i];
1505                                 Type bType = types_b [i];
1506
1507                                 if (aType.IsArray && bType.IsArray) {
1508                                         Type a_el_type = aType.GetElementType ();
1509                                         Type b_el_type = bType.GetElementType ();
1510                                         if (aType.GetArrayRank () != bType.GetArrayRank () && a_el_type == b_el_type) {
1511                                                 result = Result.RefOutArrayError;
1512                                                 continue;
1513                                         }
1514
1515                                         if (a_el_type.IsArray || b_el_type.IsArray) {
1516                                                 result = Result.ArrayArrayError;
1517                                                 continue;
1518                                         }
1519                                 }
1520
1521                                 Type aBaseType = aType;
1522                                 bool is_either_ref_or_out = false;
1523
1524                                 if (aType.IsByRef || aType.IsPointer) {
1525                                         aBaseType = aType.GetElementType ();
1526                                         is_either_ref_or_out = true;
1527                                 }
1528
1529                                 Type bBaseType = bType;
1530                                 if (bType.IsByRef || bType.IsPointer) 
1531                                 {
1532                                         bBaseType = bType.GetElementType ();
1533                                         is_either_ref_or_out = !is_either_ref_or_out;
1534                                 }
1535
1536                                 if (aBaseType != bBaseType)
1537                                         return Result.Ok;
1538
1539                                 if (is_either_ref_or_out)
1540                                         result = Result.RefOutArrayError;
1541                         }
1542                         return result;
1543                 }
1544
1545                 /// <summary>
1546                 /// Goes through all parameters and test if they are CLS-Compliant.
1547                 /// </summary>
1548                 public static bool AreParametersCompliant (Parameter[] fixedParameters, Location loc)
1549                 {
1550                         if (fixedParameters == null)
1551                                 return true;
1552
1553                         foreach (Parameter arg in fixedParameters) {
1554                                 if (!AttributeTester.IsClsCompliant (arg.ParameterType)) {
1555                                         Report.Error (3001, loc, "Argument type `{0}' is not CLS-compliant", arg.GetSignatureForError ());
1556                                         return false;
1557                                 }
1558                         }
1559                         return true;
1560                 }
1561
1562
1563                 /// <summary>
1564                 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1565                 /// </summary>
1566                 public static bool IsClsCompliant (Type type) 
1567                 {
1568                         if (type == null)
1569                                 return true;
1570
1571                         object type_compliance = analyzed_types[type];
1572                         if (type_compliance != null)
1573                                 return type_compliance == TRUE;
1574
1575                         if (type.IsPointer) {
1576                                 analyzed_types.Add (type, null);
1577                                 return false;
1578                         }
1579
1580                         bool result;
1581                         if (type.IsArray || type.IsByRef)       {
1582                                 result = IsClsCompliant (TypeManager.GetElementType (type));
1583                         } else {
1584                                 result = AnalyzeTypeCompliance (type);
1585                         }
1586                         analyzed_types.Add (type, result ? TRUE : FALSE);
1587                         return result;
1588                 }        
1589         
1590                 /// <summary>
1591                 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1592                 /// </summary>
1593                 public static IFixedBuffer GetFixedBuffer (FieldInfo fi)
1594                 {
1595                         FieldBase fb = TypeManager.GetField (fi);
1596                         if (fb != null) {
1597                                 return fb as IFixedBuffer;
1598                         }
1599
1600                         object o = fixed_buffer_cache [fi];
1601                         if (o == null) {
1602                                 if (System.Attribute.GetCustomAttribute (fi, TypeManager.fixed_buffer_attr_type) == null) {
1603                                         fixed_buffer_cache.Add (fi, FALSE);
1604                                         return null;
1605                                 }
1606                                 
1607                                 IFixedBuffer iff = new FixedFieldExternal (fi);
1608                                 fixed_buffer_cache.Add (fi, iff);
1609                                 return iff;
1610                         }
1611
1612                         if (o == FALSE)
1613                                 return null;
1614
1615                         return (IFixedBuffer)o;
1616                 }
1617
1618                 public static void VerifyModulesClsCompliance ()
1619                 {
1620                         Module[] modules = TypeManager.Modules;
1621                         if (modules == null)
1622                                 return;
1623
1624                         // The first module is generated assembly
1625                         for (int i = 1; i < modules.Length; ++i) {
1626                                 Module module = modules [i];
1627                                 if (!IsClsCompliant (module)) {
1628                                         Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute to match the assembly", module.Name);
1629                                         return;
1630                                 }
1631                         }
1632                 }
1633
1634                 public static Type GetImportedIgnoreCaseClsType (string name)
1635                 {
1636                         foreach (Assembly a in TypeManager.GetAssemblies ()) {
1637                                 Type t = a.GetType (name, false, true);
1638                                 if (t == null)
1639                                         continue;
1640
1641                                 if (IsClsCompliant (t))
1642                                         return t;
1643                         }
1644                         return null;
1645                 }
1646
1647                 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider) 
1648                 {
1649                         object[] CompliantAttribute = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1650                         if (CompliantAttribute.Length == 0)
1651                                 return false;
1652
1653                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1654                 }
1655
1656                 static bool AnalyzeTypeCompliance (Type type)
1657                 {
1658                         if (type.IsGenericInstance)
1659                                 type = type.GetGenericTypeDefinition ();
1660                         DeclSpace ds = TypeManager.LookupDeclSpace (type);
1661                         if (ds != null)
1662                                 return ds.IsClsComplianceRequired (ds);
1663
1664                         if (type.IsGenericParameter)
1665                                 return true;
1666
1667                         object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1668                         if (CompliantAttribute.Length == 0) 
1669                                 return IsClsCompliant (type.Assembly);
1670
1671                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1672                 }
1673
1674                 /// <summary>
1675                 /// Returns instance of ObsoleteAttribute when type is obsolete
1676                 /// </summary>
1677                 public static ObsoleteAttribute GetObsoleteAttribute (Type type)
1678                 {
1679                         object type_obsolete = analyzed_types_obsolete [type];
1680                         if (type_obsolete == FALSE)
1681                                 return null;
1682
1683                         if (type_obsolete != null)
1684                                 return (ObsoleteAttribute)type_obsolete;
1685
1686                         ObsoleteAttribute result = null;
1687                         if (type.IsByRef || type.IsArray || type.IsPointer) {
1688                                 result = GetObsoleteAttribute (TypeManager.GetElementType (type));
1689                         } else if (type.IsGenericParameter || type.IsGenericInstance)
1690                                 return null;
1691                         else {
1692                                 DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
1693
1694                                 // Type is external, we can get attribute directly
1695                                 if (type_ds == null) {
1696                                         object[] attribute = type.GetCustomAttributes (TypeManager.obsolete_attribute_type, false);
1697                                         if (attribute.Length == 1)
1698                                                 result = (ObsoleteAttribute)attribute [0];
1699                                 } else {
1700                                         result = type_ds.GetObsoleteAttribute ();
1701                                 }
1702                         }
1703
1704                         // Cannot use .Add because of corlib bootstrap
1705                         analyzed_types_obsolete [type] = result == null ? FALSE : result;
1706                         return result;
1707                 }
1708
1709                 /// <summary>
1710                 /// Returns instance of ObsoleteAttribute when method is obsolete
1711                 /// </summary>
1712                 public static ObsoleteAttribute GetMethodObsoleteAttribute (MethodBase mb)
1713                 {
1714                         IMethodData mc = TypeManager.GetMethod (mb);
1715                         if (mc != null) 
1716                                 return mc.GetObsoleteAttribute ();
1717
1718                         // compiler generated methods are not registered by AddMethod
1719                         if (mb.DeclaringType is TypeBuilder)
1720                                 return null;
1721
1722                         if (mb.IsSpecialName) {
1723                                 PropertyInfo pi = PropertyExpr.AccessorTable [mb] as PropertyInfo;
1724                                 if (pi != null) {
1725                                         // FIXME: This is buggy as properties from this assembly are included as well
1726                                         return null;
1727                                         //return GetMemberObsoleteAttribute (pi);
1728                                 }
1729                         }
1730
1731                         return GetMemberObsoleteAttribute (mb);
1732                 }
1733
1734                 /// <summary>
1735                 /// Returns instance of ObsoleteAttribute when member is obsolete
1736                 /// </summary>
1737                 public static ObsoleteAttribute GetMemberObsoleteAttribute (MemberInfo mi)
1738                 {
1739                         object type_obsolete = analyzed_member_obsolete [mi];
1740                         if (type_obsolete == FALSE)
1741                                 return null;
1742
1743                         if (type_obsolete != null)
1744                                 return (ObsoleteAttribute)type_obsolete;
1745
1746                         if ((mi.DeclaringType is TypeBuilder) || mi.DeclaringType.IsGenericInstance)
1747                                 return null;
1748
1749                         ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false) as ObsoleteAttribute;
1750                         analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
1751                         return oa;
1752                 }
1753
1754                 /// <summary>
1755                 /// Common method for Obsolete error/warning reporting.
1756                 /// </summary>
1757                 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc)
1758                 {
1759                         if (oa.IsError) {
1760                                 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1761                                 return;
1762                         }
1763
1764                         if (oa.Message == null) {
1765                                 Report.Warning (612, loc, "`{0}' is obsolete", member);
1766                                 return;
1767                         }
1768                         if (RootContext.WarningLevel >= 2)
1769                                 Report.Warning (618, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1770                 }
1771
1772                 public static bool IsConditionalMethodExcluded (MethodBase mb)
1773                 {
1774                         object excluded = analyzed_method_excluded [mb];
1775                         if (excluded != null)
1776                                 return excluded == TRUE ? true : false;
1777
1778                         if (mb.Mono_IsInflatedMethod)
1779                                 return false;
1780                         
1781                         ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[];
1782                         if (attrs.Length == 0) {
1783                                 analyzed_method_excluded.Add (mb, FALSE);
1784                                 return false;
1785                         }
1786
1787                         foreach (ConditionalAttribute a in attrs) {
1788                                 if (RootContext.AllDefines.Contains (a.ConditionString)) {
1789                                         analyzed_method_excluded.Add (mb, FALSE);
1790                                         return false;
1791                                 }
1792                         }
1793                         analyzed_method_excluded.Add (mb, TRUE);
1794                         return true;
1795                 }
1796
1797                 /// <summary>
1798                 /// Analyzes class whether it has attribute which has ConditionalAttribute
1799                 /// and its condition is not defined.
1800                 /// </summary>
1801                 public static bool IsAttributeExcluded (Type type)
1802                 {
1803                         if (!type.IsClass)
1804                                 return false;
1805
1806                         Class class_decl = TypeManager.LookupDeclSpace (type) as Class;
1807
1808                         // TODO: add caching
1809                         // TODO: merge all Type bases attribute caching to one cache to save memory
1810                         if (class_decl == null) {
1811                                 object[] attributes = type.GetCustomAttributes (TypeManager.conditional_attribute_type, false);
1812                                 foreach (ConditionalAttribute ca in attributes) {
1813                                         if (RootContext.AllDefines.Contains (ca.ConditionString))
1814                                                 return false;
1815                                 }
1816                                 return attributes.Length > 0;
1817                         }
1818
1819                         return class_decl.IsExcluded ();
1820                 }
1821         }
1822 }