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