2004-02-03 Marek Safar <marek.safar@seznam.cz>
[mono.git] / mcs / mcs / attribute.cs
1 //
2 // attribute.cs: Attribute Handler
3 //
4 // Author: Ravi Pratap (ravi@ximian.com)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10 //
11
12 using System;
13 using System.Diagnostics;
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Runtime.InteropServices;
18 using System.Runtime.CompilerServices;
19 using System.Text;
20
21 namespace Mono.CSharp {
22
23         public class Attribute {
24                 public readonly string    Name;
25                 public readonly ArrayList Arguments;
26
27                 Location Location;
28
29                 public Type Type;
30                 
31                 //
32                 // The following are only meaningful when the attribute
33                 // being emitted is an AttributeUsage attribute
34                 //
35                 AttributeTargets Targets;
36                 bool AllowMultiple;
37                 bool Inherited;
38
39                 bool UsageAttr = false;
40                 
41                 MethodImplOptions ImplOptions;
42                 UnmanagedType     UnmanagedType;
43                 CustomAttributeBuilder cb;
44         
45                 // non-null if named args present after Resolve () is called
46                 PropertyInfo [] prop_info_arr;
47                 FieldInfo [] field_info_arr;
48                 object [] field_values_arr;
49                 object [] prop_values_arr;
50                 
51                 public Attribute (string name, ArrayList args, Location loc)
52                 {
53                         Name = name;
54                         Arguments = args;
55                         Location = loc;
56                 }
57
58                 void Error_InvalidNamedArgument (string name)
59                 {
60                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
61                                       "argument. Named attribute arguments must be fields which are not " +
62                                       "readonly, static or const, or properties with a set accessor which "+
63                                       "are not static.");
64                 }
65
66                 static void Error_AttributeArgumentNotValid (Location loc)
67                 {
68                         Report.Error (182, loc,
69                                       "An attribute argument must be a constant expression, typeof " +
70                                       "expression or array creation expression");
71                 }
72
73                 static void Error_AttributeConstructorMismatch (Location loc)
74                 {
75                         Report.Error (-6, loc,
76                                       "Could not find a constructor for this argument list.");
77                 }
78
79                 /// <summary>
80                 ///   Tries to resolve the type of the attribute. Flags an error if it can't.
81                 /// </summary>
82                 private Type CheckAttributeType (EmitContext ec) {
83                         Type t;
84                         bool isattributeclass = true;
85                         
86                         t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
87                         if (t != null) {
88                                 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
89                                 if (isattributeclass)
90                                         return t;
91                         }
92                         t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
93                         if (t != null) {
94                                 if (t.IsSubclassOf (TypeManager.attribute_type))
95                                         return t;
96                         }
97                         if (!isattributeclass) {
98                                 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
99                                 return null;
100                         }
101                         if (t != null) {
102                                 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
103                                 return null;
104                         }
105                         Report.Error (
106                                 246, Location, "Could not find attribute '" + Name + "' (are you" +
107                                 " missing a using directive or an assembly reference ?)");
108                         return null;
109                 }
110
111                 public Type ResolveType (EmitContext ec)
112                 {
113                         Type = CheckAttributeType (ec);
114                         return Type;
115                 }
116
117                 /// <summary>
118                 ///   Validates the guid string
119                 /// </summary>
120                 bool ValidateGuid (string guid)
121                 {
122                         try {
123                                 new Guid (guid);
124                                 return true;
125                         } catch {
126                                 Report.Error (647, Location, "Format of GUID is invalid: " + guid);
127                                 return false;
128                         }
129                 }
130
131                 //
132                 // Given an expression, if the expression is a valid attribute-argument-expression
133                 // returns an object that can be used to encode it, or null on failure.
134                 //
135                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)
136                 {
137                         if (e is Constant) {
138                                 result = ((Constant) e).GetValue ();
139                                 return true;
140                         } else if (e is TypeOf) {
141                                 result = ((TypeOf) e).TypeArg;
142                                 return true;
143                         } else if (e is ArrayCreation){
144                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();
145                                 if (result != null)
146                                         return true;
147                         } else if (e is EmptyCast) {
148                                 result = e;
149                                 if (((EmptyCast) e).Child is Constant) {
150                                         result = ((Constant) ((EmptyCast)e).Child).GetValue();
151                                 }
152                                 return true;
153                         }
154
155                         result = null;
156                         Error_AttributeArgumentNotValid (loc);
157                         return false;
158                 }
159                 
160                 public CustomAttributeBuilder Resolve (EmitContext ec)
161                 {
162                         if (Type == null)
163                                 Type = CheckAttributeType (ec);
164                         if (Type == null)
165                                 return null;
166
167                         bool MethodImplAttr = false;
168                         bool MarshalAsAttr = false;
169                         bool GuidAttr = false;
170                         UsageAttr = false;
171
172                         bool DoCompares = true;
173
174                         //
175                         // If we are a certain special attribute, we
176                         // set the information accordingly
177                         //
178                         
179                         if (Type == TypeManager.attribute_usage_type)
180                                 UsageAttr = true;
181                         else if (Type == TypeManager.methodimpl_attr_type)
182                                 MethodImplAttr = true;
183                         else if (Type == TypeManager.marshal_as_attr_type)
184                                 MarshalAsAttr = true;
185                         else if (Type == TypeManager.guid_attr_type)
186                                 GuidAttr = true;
187                         else
188                                 DoCompares = false;
189
190                         // Now we extract the positional and named arguments
191                         
192                         ArrayList pos_args = new ArrayList ();
193                         ArrayList named_args = new ArrayList ();
194                         int pos_arg_count = 0;
195                         
196                         if (Arguments != null) {
197                                 pos_args = (ArrayList) Arguments [0];
198                                 if (pos_args != null)
199                                         pos_arg_count = pos_args.Count;
200                                 if (Arguments.Count > 1)
201                                         named_args = (ArrayList) Arguments [1];
202                         }
203
204                         object [] pos_values = new object [pos_arg_count];
205
206                         //
207                         // First process positional arguments 
208                         //
209
210                         int i;
211                         for (i = 0; i < pos_arg_count; i++) {
212                                 Argument a = (Argument) pos_args [i];
213                                 Expression e;
214
215                                 if (!a.Resolve (ec, Location))
216                                         return null;
217
218                                 e = a.Expr;
219
220                                 object val;
221                                 if (!GetAttributeArgumentExpression (e, Location, out val))
222                                         return null;
223                                 
224                                 pos_values [i] = val;
225                                 if (DoCompares){
226                                         if (UsageAttr)
227                                                 this.Targets = (AttributeTargets) pos_values [0];
228                                         else if (MethodImplAttr)
229                                                 this.ImplOptions = (MethodImplOptions) pos_values [0];
230                                         else if (GuidAttr){
231                                                 //
232                                                 // we will later check the validity of the type
233                                                 //
234                                                 if (pos_values [0] is string){
235                                                         if (!ValidateGuid ((string) pos_values [0]))
236                                                                 return null;
237                                                 }
238                                                 
239                                         } else if (MarshalAsAttr)
240                                                 this.UnmanagedType =
241                                                 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
242                                 }
243                         }
244
245                         //
246                         // Now process named arguments
247                         //
248
249                         ArrayList field_infos = null;
250                         ArrayList prop_infos  = null;
251                         ArrayList field_values = null;
252                         ArrayList prop_values = null;
253
254                         if (named_args.Count > 0) {
255                                 field_infos = new ArrayList ();
256                                 prop_infos  = new ArrayList ();
257                                 field_values = new ArrayList ();
258                                 prop_values = new ArrayList ();
259                         }
260                         
261                         for (i = 0; i < named_args.Count; i++) {
262                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
263                                 string member_name = (string) de.Key;
264                                 Argument a  = (Argument) de.Value;
265                                 Expression e;
266                                 
267                                 if (!a.Resolve (ec, Location))
268                                         return null;
269
270                                 Expression member = Expression.MemberLookup (
271                                         ec, Type, member_name,
272                                         MemberTypes.Field | MemberTypes.Property,
273                                         BindingFlags.Public | BindingFlags.Instance,
274                                         Location);
275
276                                 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
277                                         Error_InvalidNamedArgument (member_name);
278                                         return null;
279                                 }
280
281                                 e = a.Expr;
282                                 if (member is PropertyExpr) {
283                                         PropertyExpr pe = (PropertyExpr) member;
284                                         PropertyInfo pi = pe.PropertyInfo;
285
286                                         if (!pi.CanWrite) {
287                                                 Error_InvalidNamedArgument (member_name);
288                                                 return null;
289                                         }
290
291                                         if (e is Constant) {
292                                                 object o = ((Constant) e).GetValue ();
293                                                 prop_values.Add (o);
294                                                 
295                                                 if (UsageAttr) {
296                                                         if (member_name == "AllowMultiple")
297                                                                 this.AllowMultiple = (bool) o;
298                                                         if (member_name == "Inherited")
299                                                                 this.Inherited = (bool) o;
300                                                 }
301                                                 
302                                         } else if (e is TypeOf) {
303                                                 prop_values.Add (((TypeOf) e).TypeArg);
304                                         } else if (e is ArrayCreation) {
305                                                 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());
306                                         } else {
307                                                 Error_AttributeArgumentNotValid (Location);
308                                                 return null;
309                                         }
310                                         
311                                         prop_infos.Add (pi);
312                                         
313                                 } else if (member is FieldExpr) {
314                                         FieldExpr fe = (FieldExpr) member;
315                                         FieldInfo fi = fe.FieldInfo;
316
317                                         if (fi.IsInitOnly) {
318                                                 Error_InvalidNamedArgument (member_name);
319                                                 return null;
320                                         }
321
322                                         //
323                                         // Handle charset here, and set the TypeAttributes
324                                         
325                                         if (e is Constant){
326                                                 object value = ((Constant) e).GetValue ();
327                                                 
328                                                 field_values.Add (value);
329                                         } else if (e is TypeOf) {
330                                                 field_values.Add (((TypeOf) e).TypeArg);
331                                         } else {
332                                                 Error_AttributeArgumentNotValid (Location);
333                                                 return null;
334                                         }
335                                         
336                                         field_infos.Add (fi);
337                                 }
338                         }
339
340                         Expression mg = Expression.MemberLookup (
341                                 ec, Type, ".ctor", MemberTypes.Constructor,
342                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
343                                 Location);
344
345                         if (mg == null) {
346                                 Error_AttributeConstructorMismatch (Location);
347                                 return null;
348                         }
349
350                         MethodBase constructor = Invocation.OverloadResolve (
351                                 ec, (MethodGroupExpr) mg, pos_args, Location);
352
353                         if (constructor == null) {
354                                 Error_AttributeConstructorMismatch (Location);
355                                 return null;
356                         }
357
358                         //
359                         // Now we perform some checks on the positional args as they
360                         // cannot be null for a constructor which expects a parameter
361                         // of type object
362                         //
363
364                         ParameterData pd = Invocation.GetParameterData (constructor);
365
366                         int group_in_params_array = Int32.MaxValue;
367                         int pc = pd.Count;
368                         if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
369                                 group_in_params_array = pc-1;
370                         
371                         for (int j = 0; j < pos_arg_count; ++j) {
372                                 Argument a = (Argument) pos_args [j];
373                                 
374                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
375                                         Error_AttributeArgumentNotValid (Location);
376                                         return null;
377                                 }
378
379                                 if (j < group_in_params_array)
380                                         continue;
381                                 
382                                 if (j == group_in_params_array){
383                                         object v = pos_values [j];
384                                         int count = pos_arg_count - j;
385
386                                         object [] array = new object [count];
387                                         pos_values [j] = array;
388                                         array [0] = v;
389                                 } else {
390                                         object [] array = (object []) pos_values [group_in_params_array];
391
392                                         array [j - group_in_params_array] = pos_values [j];
393                                 }
394                         }
395
396                         //
397                         // Adjust the size of the pos_values if it had params
398                         //
399                         if (group_in_params_array != Int32.MaxValue){
400                                 int argc = group_in_params_array+1;
401                                 object [] new_pos_values = new object [argc];
402
403                                 for (int p = 0; p < argc; p++)
404                                         new_pos_values [p] = pos_values [p];
405                                 pos_values = new_pos_values;
406                         }
407
408                         try {
409                                 if (named_args.Count > 0) {
410                                         prop_info_arr = new PropertyInfo [prop_infos.Count];
411                                         field_info_arr = new FieldInfo [field_infos.Count];
412                                         field_values_arr = new object [field_values.Count];
413                                         prop_values_arr = new object [prop_values.Count];
414
415                                         field_infos.CopyTo  (field_info_arr, 0);
416                                         field_values.CopyTo (field_values_arr, 0);
417
418                                         prop_values.CopyTo  (prop_values_arr, 0);
419                                         prop_infos.CopyTo   (prop_info_arr, 0);
420
421                                         cb = new CustomAttributeBuilder (
422                                                 (ConstructorInfo) constructor, pos_values,
423                                                 prop_info_arr, prop_values_arr,
424                                                 field_info_arr, field_values_arr);
425                                 }
426                                 else
427                                         cb = new CustomAttributeBuilder (
428                                                 (ConstructorInfo) constructor, pos_values);
429                         } catch (NullReferenceException) {
430                                 // 
431                                 // Don't know what to do here
432                                 //
433                                 Report.Warning (
434                                         -101, Location, "NullReferenceException while trying to create attribute." +
435                                         "Something's wrong!");
436                         } catch (Exception e) {
437                                 //
438                                 // Sample:
439                                 // using System.ComponentModel;
440                                 // [DefaultValue (CollectionChangeAction.Add)]
441                                 // class X { static void Main () {} }
442                                 //
443                                 Report.Warning (
444                                         -23, Location,
445                                         "The compiler can not encode this attribute in .NET due to\n" +
446                                         "\ta bug in the .NET runtime.  Try the Mono runtime.\nThe error was: " + e.Message);
447                         }
448                         
449                         return cb;
450                 }
451
452                 /// <summary>
453                 ///   Get a string containing a list of valid targets for the attribute 'attr'
454                 /// </summary>
455                 static string GetValidTargets (Attribute attr)
456                 {
457                         StringBuilder sb = new StringBuilder ();
458                         AttributeTargets targets = 0;
459                         
460                         TypeContainer a = TypeManager.LookupAttr (attr.Type);
461
462                         if (a == null) {
463                                 
464                                 System.Attribute [] attrs = null;
465                                 
466                                 try {
467                                         attrs = System.Attribute.GetCustomAttributes (attr.Type);
468                                         
469                                 } catch {
470                                         Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
471                                                       " (maybe you forgot to set the usage using the" +
472                                                       " AttributeUsage attribute ?).");
473                                         return null;
474                                 }
475                                         
476                                 foreach (System.Attribute tmp in attrs)
477                                         if (tmp is AttributeUsageAttribute) {
478                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;
479                                                 break;
480                                         }
481                         } else
482                                 targets = a.Targets;
483
484                         
485                         if ((targets & AttributeTargets.Assembly) != 0)
486                                 sb.Append ("'assembly' ");
487
488                         if ((targets & AttributeTargets.Class) != 0)
489                                 sb.Append ("'class' ");
490
491                         if ((targets & AttributeTargets.Constructor) != 0)
492                                 sb.Append ("'constructor' ");
493
494                         if ((targets & AttributeTargets.Delegate) != 0)
495                                 sb.Append ("'delegate' ");
496
497                         if ((targets & AttributeTargets.Enum) != 0)
498                                 sb.Append ("'enum' ");
499
500                         if ((targets & AttributeTargets.Event) != 0)
501                                 sb.Append ("'event' ");
502
503                         if ((targets & AttributeTargets.Field) != 0)
504                                 sb.Append ("'field' ");
505
506                         if ((targets & AttributeTargets.Interface) != 0)
507                                 sb.Append ("'interface' ");
508
509                         if ((targets & AttributeTargets.Method) != 0)
510                                 sb.Append ("'method' ");
511
512                         if ((targets & AttributeTargets.Module) != 0)
513                                 sb.Append ("'module' ");
514
515                         if ((targets & AttributeTargets.Parameter) != 0)
516                                 sb.Append ("'parameter' ");
517
518                         if ((targets & AttributeTargets.Property) != 0)
519                                 sb.Append ("'property' ");
520
521                         if ((targets & AttributeTargets.ReturnValue) != 0)
522                                 sb.Append ("'return value' ");
523
524                         if ((targets & AttributeTargets.Struct) != 0)
525                                 sb.Append ("'struct' ");
526
527                         return sb.ToString ();
528
529                 }
530
531                 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
532                 {
533                         Report.Error (
534                                 592, loc, "Attribute '" + a.Name +
535                                 "' is not valid on this declaration type. " +
536                                 "It is valid on " + GetValidTargets (a) + "declarations only.");
537                 }
538
539                 /// <summary>
540                 ///   Ensure that Attribute 'a' is being applied to the right language element (target)
541                 /// </summary>
542                 public static bool CheckAttributeTarget (Attribute a, object element)
543                 {
544                         TypeContainer attr = TypeManager.LookupAttr (a.Type);
545                         AttributeTargets targets = 0;
546
547                         if (attr == null) {
548                                 System.Attribute [] attrs = null;
549                                 
550                                 try {
551                                         attrs = System.Attribute.GetCustomAttributes (a.Type);
552
553                                 } catch {
554                                         Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
555                                                       " (maybe you forgot to set the usage using the" +
556                                                       " AttributeUsage attribute ?).");
557                                         return false;
558                                 }
559                                         
560                                 foreach (System.Attribute tmp in attrs)
561                                         if (tmp is AttributeUsageAttribute) { 
562                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;
563                                                 break;
564                                         }
565                         } else
566                                 targets = attr.Targets;
567
568
569                         if (element is Class) {
570                                 if ((targets & AttributeTargets.Class) != 0)
571                                         return true;
572                                 else
573                                         return false;
574                                 
575                         } else if (element is Struct) {
576                                 if ((targets & AttributeTargets.Struct) != 0)
577                                         return true;
578                                 else
579                                         return false;
580                         } else if (element is Constructor) {
581                                 if ((targets & AttributeTargets.Constructor) != 0)
582                                         return true;
583                                 else
584                                         return false;
585                         } else if (element is Delegate) {
586                                 if ((targets & AttributeTargets.Delegate) != 0)
587                                         return true;
588                                 else
589                                         return false;
590                         } else if (element is Enum) {
591                                 if ((targets & AttributeTargets.Enum) != 0)
592                                         return true;
593                                 else
594                                         return false;
595                         } else if (element is Event || element is InterfaceEvent) {
596                                 if ((targets & AttributeTargets.Event) != 0)
597                                         return true;
598                                 else
599                                         return false;
600                         } else if (element is Field || element is FieldBuilder) {
601                                 if ((targets & AttributeTargets.Field) != 0)
602                                         return true;
603                                 else
604                                         return false;
605                         } else if (element is Interface) {
606                                 if ((targets & AttributeTargets.Interface) != 0)
607                                         return true;
608                                 else
609                                         return false;
610                         } else if (element is Method || element is Operator ||
611                                    element is InterfaceMethod || element is Accessor) {
612                                 if ((targets & AttributeTargets.Method) != 0)
613                                         return true;
614                                 else
615                                         return false;
616                         } else if (element is ParameterBuilder) {
617                                 if ((targets & AttributeTargets.Parameter) != 0 ||
618                                     (targets & AttributeTargets.ReturnValue) != 0)
619                                         return true;
620                                 else
621                                         return false;
622                         } else if (element is Property || element is Indexer ||
623                                    element is InterfaceProperty || element is InterfaceIndexer) {
624                                 if ((targets & AttributeTargets.Property) != 0)
625                                         return true;
626                                 else
627                                         return false;
628                         } else if (element is AssemblyBuilder){
629                                 if ((targets & AttributeTargets.Assembly) != 0)
630                                         return true;
631                                 else
632                                         return false;
633                         }
634
635                         return false;
636                 }
637
638                 //
639                 // This method should be invoked to pull the IndexerName attribute from an
640                 // Indexer if it exists.
641                 //
642                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
643                 {
644                         if (opt_attrs == null)
645                                 return null;
646                         if (opt_attrs.AttributeSections == null)
647                                 return null;
648
649                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {
650                                 if (asec.Attributes == null)
651                                         continue;
652
653                                 foreach (Attribute a in asec.Attributes){
654                                         if (a.ResolveType (ec) == null)
655                                                 return null;
656                                         
657                                         if (a.Type != TypeManager.indexer_name_type)
658                                                 continue;
659
660                                         //
661                                         // So we have found an IndexerName, pull the data out.
662                                         //
663                                         if (a.Arguments == null || a.Arguments [0] == null){
664                                                 Error_AttributeConstructorMismatch (a.Location);
665                                                 return null;
666                                         }
667                                         ArrayList pos_args = (ArrayList) a.Arguments [0];
668                                         if (pos_args.Count == 0){
669                                                 Error_AttributeConstructorMismatch (a.Location);
670                                                 return null;
671                                         }
672                                         
673                                         Argument arg = (Argument) pos_args [0];
674                                         if (!arg.Resolve (ec, a.Location))
675                                                 return null;
676                                         
677                                         Expression e = arg.Expr;
678                                         if (!(e is StringConstant)){
679                                                 Error_AttributeConstructorMismatch (a.Location);
680                                                 return null;
681                                         }
682
683                                         //
684                                         // Remove the attribute from the list
685                                         //
686                                         asec.Attributes.Remove (a);
687
688                                         return (((StringConstant) e).Value);
689                                 }
690                         }
691                         return null;
692                 }
693
694                 //
695                 // This pulls the condition name out of a Conditional attribute
696                 //
697                 public string Conditional_GetConditionName ()
698                 {
699                         //
700                         // So we have a Conditional, pull the data out.
701                         //
702                         if (Arguments == null || Arguments [0] == null){
703                                 Error_AttributeConstructorMismatch (Location);
704                                 return null;
705                         }
706
707                         ArrayList pos_args = (ArrayList) Arguments [0];
708                         if (pos_args.Count != 1){
709                                 Error_AttributeConstructorMismatch (Location);
710                                 return null;
711                         }
712
713                         Argument arg = (Argument) pos_args [0]; 
714                         if (!(arg.Expr is StringConstant)){
715                                 Error_AttributeConstructorMismatch (Location);
716                                 return null;
717                         }
718
719                         return ((StringConstant) arg.Expr).Value;
720                 }
721
722                 //
723                 // This pulls the obsolete message and error flag out of an Obsolete attribute
724                 //
725                 public string Obsolete_GetObsoleteMessage (out bool is_error)
726                 {
727                         is_error = false;
728                         //
729                         // So we have an Obsolete, pull the data out.
730                         //
731                         if (Arguments == null || Arguments [0] == null)
732                                 return "";
733
734                         ArrayList pos_args = (ArrayList) Arguments [0];
735                         if (pos_args.Count == 0)
736                                 return "";
737                         else if (pos_args.Count > 2){
738                                 Error_AttributeConstructorMismatch (Location);
739                                 return null;
740                         }
741
742                         Argument arg = (Argument) pos_args [0]; 
743                         if (!(arg.Expr is StringConstant)){
744                                 Error_AttributeConstructorMismatch (Location);
745                                 return null;
746                         }
747
748                         if (pos_args.Count == 2){
749                                 Argument arg2 = (Argument) pos_args [1];
750                                 if (!(arg2.Expr is BoolConstant)){
751                                         Error_AttributeConstructorMismatch (Location);
752                                         return null;
753                                 }
754                                 is_error = ((BoolConstant) arg2.Expr).Value;
755                         }
756
757                         return ((StringConstant) arg.Expr).Value;
758                 }
759
760                 static object GetFieldValue (Attribute a, string name)
761                 {
762                         int i;
763                         if (a.field_info_arr == null)
764                                 return null;
765                         i = 0;
766                         foreach (FieldInfo fi in a.field_info_arr) {
767                                 if (fi.Name == name)
768                                         return a.field_values_arr [i];
769                                 i++;
770                         }
771                         return null;
772                 }
773
774                 static UnmanagedMarshal GetMarshal (Attribute a)
775                 {
776                         object o = GetFieldValue (a, "ArraySubType");
777                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
778                         
779                         switch (a.UnmanagedType) {
780                         case UnmanagedType.CustomMarshaler:
781                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
782                                                                        BindingFlags.Static | BindingFlags.Public);
783                                 if (define_custom == null)
784                                         return null;
785                                 
786                                 object [] args = new object [4];
787                                 args [0] = GetFieldValue (a, "MarshalTypeRef");
788                                 args [1] = GetFieldValue (a, "MarshalCookie");
789                                 args [2] = GetFieldValue (a, "MarshalType");
790                                 args [3] = Guid.Empty;
791                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);
792                                 
793                         case UnmanagedType.LPArray:                             
794                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);
795                         
796                         case UnmanagedType.SafeArray:
797                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
798                         
799                         case UnmanagedType.ByValArray:
800                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));
801                         
802                         case UnmanagedType.ByValTStr:
803                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));
804                         
805                         default:
806                                 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
807                         }
808                 }
809
810                 /// <summary>
811                 ///   Applies the attributes specified on target 'kind' to the `builder'.
812                 /// </summary>
813                 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
814                                                     Attributes opt_attrs)
815                 {
816                         Type attr_type = null;
817                         
818                         if (opt_attrs == null)
819                                 return;
820                         if (opt_attrs.AttributeSections == null)
821                                 return;
822
823                         ArrayList emitted_attrs = new ArrayList ();
824                         ArrayList emitted_targets = new ArrayList ();
825
826                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {
827                                 string attr_target = asec.Target;
828                                 
829                                 if (asec.Attributes == null)
830                                         continue;
831
832                                 if (attr_target == "assembly" && !(builder is AssemblyBuilder))
833                                         continue;
834
835                                 if (attr_target == "return" && !(builder is ParameterBuilder))
836                                         continue;
837                                 
838                                 foreach (Attribute a in asec.Attributes) {
839                                         Location loc = a.Location;
840                                         CustomAttributeBuilder cb = a.Resolve (ec);
841                                         attr_type = a.Type;
842
843                                         if (cb == null) 
844                                                 continue;
845                                         
846                                         if (!(kind is TypeContainer))
847                                                 if (!CheckAttributeTarget (a, kind)) {
848                                                         Error_AttributeNotValidForElement (a, loc);
849                                                         return;
850                                                 }
851
852                                         //
853                                         // Perform the check for duplicate attributes
854                                         //
855                                         if (emitted_attrs.Contains (attr_type) &&
856                                             emitted_targets.Contains (attr_target) &&
857                                             !TypeManager.AreMultipleAllowed (attr_type)) {
858                                                 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
859                                                 return;
860                                         }
861
862                                         if (kind is Method || kind is Operator || kind is InterfaceMethod ||
863                                             kind is Accessor) {
864                                                 if (attr_type == TypeManager.methodimpl_attr_type) {
865                                                         if (a.ImplOptions == MethodImplOptions.InternalCall)
866                                                                 ((MethodBuilder) builder).
867                                                                 SetImplementationFlags (
868                                                                         MethodImplAttributes.InternalCall |
869                                                                         MethodImplAttributes.Runtime);
870                                                         else
871                                                                 ((MethodBuilder) builder).SetCustomAttribute (cb);
872                                                 } else if (attr_type != TypeManager.dllimport_type){
873                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);
874                                                 }
875                                         } else if (kind is Constructor) {
876                                                 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
877                                         } else if (kind is Field) {
878                                                 if (attr_type == TypeManager.marshal_as_attr_type) {
879                                                         UnmanagedMarshal marshal = GetMarshal (a);
880                                                         if (marshal == null) {
881                                                                 Report.Warning (-24, loc,
882                                                                         "The Microsoft Runtime cannot set this marshal info. " +
883                                                                         "Please use the Mono runtime instead.");
884                                                         } else {
885                                                                 ((FieldBuilder) builder).SetMarshal (marshal);
886                                                         }
887                                                 } else { 
888                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);
889                                                 }
890                                         } else if (kind is Property || kind is Indexer ||
891                                                    kind is InterfaceProperty || kind is InterfaceIndexer) {
892
893                                                 if (builder is PropertyBuilder) 
894                                                         ((PropertyBuilder) builder).SetCustomAttribute (cb);
895                                                 //
896                                                 // This is for the case we are setting attributes on
897                                                 // the get and set accessors
898                                                 //
899                                                 else if (builder is MethodBuilder)
900                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);
901                                         } else if (kind is Event || kind is InterfaceEvent) {
902                                                 ((MyEventBuilder) builder).SetCustomAttribute (cb);
903                                         } else if (kind is ParameterBuilder) {
904
905                                                 if (attr_type == TypeManager.marshal_as_attr_type) {
906                                                         UnmanagedMarshal marshal = GetMarshal (a);
907                                                         if (marshal == null) {
908                                                                 Report.Warning (-24, loc,
909                                                                         "The Microsoft Runtime cannot set this marshal info. " +
910                                                                         "Please use the Mono runtime instead.");
911                                                         } else {
912                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);
913                                                         }
914                                                 } else { 
915
916                                                         try {
917                                                                 ((ParameterBuilder) builder).SetCustomAttribute (cb);
918                                                         } catch (System.ArgumentException) {
919                                                                 Report.Warning (-24, loc,
920                                                                                 "The Microsoft Runtime cannot set attributes \n" +
921                                                                                 "on the return type of a method. Please use the \n" +
922                                                                                 "Mono runtime instead.");
923                                                         }
924
925                                                 }
926                                         } else if (kind is Enum) {
927                                                 ((TypeBuilder) builder).SetCustomAttribute (cb); 
928
929                                         } else if (kind is TypeContainer) {
930                                                 TypeContainer tc = (TypeContainer) kind;
931                                                 
932                                                 if (a.UsageAttr) {
933                                                         tc.Targets = a.Targets;
934                                                         tc.AllowMultiple = a.AllowMultiple;
935                                                         tc.Inherited = a.Inherited;
936
937                                                         TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
938                                                                                                     tc.AllowMultiple);
939                                                         
940                                                 } else if (attr_type == TypeManager.default_member_type) {
941                                                         if (tc.Indexers != null) {
942                                                                 Report.Error (646, loc,
943                                                                       "Cannot specify the DefaultMember attribute on" +
944                                                                       " a type containing an indexer");
945                                                                 return;
946                                                         }
947
948                                                 } else {
949                                                         if (!CheckAttributeTarget (a, kind)) {
950                                                                 Error_AttributeNotValidForElement (a, loc);
951                                                                 return;
952                                                         }
953                                                 }
954
955                                                 try {
956                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);
957                                                 } catch (System.ArgumentException) {
958                                                         Report.Warning (
959                                                                 -21, loc,
960                                                 "The CharSet named property on StructLayout\n"+
961                                                 "\tdoes not work correctly on Microsoft.NET\n"+
962                                                 "\tYou might want to remove the CharSet declaration\n"+
963                                                 "\tor compile using the Mono runtime instead of the\n"+
964                                                 "\tMicrosoft .NET runtime");
965                                                 }
966                                         } else if (kind is Delegate){
967                                                 if (!CheckAttributeTarget (a, kind)) {
968                                                         Error_AttributeNotValidForElement (a, loc);
969                                                         return;
970                                                 }
971                                                 try {
972                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);
973                                                 } catch (System.ArgumentException) {
974                                                         Report.Warning (
975                                                                 -21, loc,
976                                                 "The CharSet named property on StructLayout\n"+
977                                                 "\tdoes not work correctly on Microsoft.NET\n"+
978                                                 "\tYou might want to remove the CharSet declaration\n"+
979                                                 "\tor compile using the Mono runtime instead of the\n"+
980                                                 "\tMicrosoft .NET runtime");
981                                                 }
982                                         } else if (kind is Interface) {
983                                                 Interface iface = (Interface) kind;
984
985                                                 if ((attr_type == TypeManager.default_member_type) &&
986                                                     (iface.InterfaceIndexers != null)) {
987                                                         Report.Error (
988                                                                 646, loc,
989                                                                 "Cannot specify the DefaultMember attribute on" +
990                                                                 " a type containing an indexer");
991                                                         return;
992                                                 }
993
994                                                 if (!CheckAttributeTarget (a, kind)) {
995                                                         Error_AttributeNotValidForElement (a, loc);
996                                                         return;
997                                                 }
998
999                                                 ((TypeBuilder) builder).SetCustomAttribute (cb);
1000                                         } else if (kind is AssemblyBuilder){
1001                                                 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
1002                                         } else if (kind is ModuleBuilder) {
1003                                                 ((ModuleBuilder) builder).SetCustomAttribute (cb);
1004                                         } else if (kind is FieldBuilder) {
1005                                                 if (attr_type == TypeManager.marshal_as_attr_type) {
1006                                                         UnmanagedMarshal marshal = GetMarshal (a);
1007                                                         if (marshal == null) {
1008                                                                 Report.Warning (-24, loc,
1009                                                                         "The Microsoft Runtime cannot set this marshal info. " +
1010                                                                         "Please use the Mono runtime instead.");
1011                                                         } else {
1012                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);
1013                                                         }
1014                                                 } else { 
1015                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);
1016                                                 }
1017                                         } else
1018                                                 throw new Exception ("Unknown kind: " + kind);
1019
1020                                         //
1021                                         // Once an attribute type has been emitted once we
1022                                         // keep track of the info to prevent multiple occurences
1023                                         // for attributes which do not explicitly allow it
1024                                         //
1025                                         if (!emitted_attrs.Contains (attr_type))
1026                                                 emitted_attrs.Add (attr_type);
1027
1028                                         //
1029                                         // We keep of this target-wise and so emitted targets
1030                                         // are tracked too
1031                                         //
1032                                         if (!emitted_targets.Contains (attr_target))
1033                                                 emitted_targets.Add (attr_target);
1034                                 }
1035                                 
1036                                 
1037                         }
1038                 }
1039
1040                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
1041                                                           MethodAttributes flags, Type ret_type, Type [] param_types)
1042                 {
1043                         //
1044                         // We extract from the attribute the information we need 
1045                         //
1046
1047                         if (Arguments == null) {
1048                                 Console.WriteLine ("Internal error : this is not supposed to happen !");
1049                                 return null;
1050                         }
1051
1052                         Type = CheckAttributeType (ec);
1053                         if (Type == null)
1054                                 return null;
1055                         
1056                         ArrayList named_args = new ArrayList ();
1057                         
1058                         ArrayList pos_args = (ArrayList) Arguments [0];
1059                         if (Arguments.Count > 1)
1060                                 named_args = (ArrayList) Arguments [1];
1061                         
1062
1063                         string dll_name = null;
1064                         
1065                         Argument tmp = (Argument) pos_args [0];
1066
1067                         if (!tmp.Resolve (ec, Location))
1068                                 return null;
1069                         
1070                         if (tmp.Expr is Constant)
1071                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
1072                         else { 
1073                                 Error_AttributeArgumentNotValid (Location);
1074                                 return null;
1075                         }
1076
1077                         // Now we process the named arguments
1078                         CallingConvention cc = CallingConvention.Winapi;
1079                         CharSet charset = CharSet.Ansi;
1080                         bool preserve_sig = true;
1081 #if FIXME
1082                         bool exact_spelling = false;
1083 #endif
1084                         bool set_last_err = false;
1085                         string entry_point = null;
1086
1087                         for (int i = 0; i < named_args.Count; i++) {
1088
1089                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
1090
1091                                 string member_name = (string) de.Key;
1092                                 Argument a  = (Argument) de.Value;
1093
1094                                 if (!a.Resolve (ec, Location))
1095                                         return null;
1096
1097                                 Expression member = Expression.MemberLookup (
1098                                         ec, Type, member_name, 
1099                                         MemberTypes.Field | MemberTypes.Property,
1100                                         BindingFlags.Public | BindingFlags.Instance,
1101                                         Location);
1102
1103                                 if (member == null || !(member is FieldExpr)) {
1104                                         Error_InvalidNamedArgument (member_name);
1105                                         return null;
1106                                 }
1107
1108                                 if (member is FieldExpr) {
1109                                         FieldExpr fe = (FieldExpr) member;
1110                                         FieldInfo fi = fe.FieldInfo;
1111
1112                                         if (fi.IsInitOnly) {
1113                                                 Error_InvalidNamedArgument (member_name);
1114                                                 return null;
1115                                         }
1116
1117                                         if (a.Expr is Constant) {
1118                                                 Constant c = (Constant) a.Expr;
1119                                                 
1120                                                 if (member_name == "CallingConvention")
1121                                                         cc = (CallingConvention) c.GetValue ();
1122                                                 else if (member_name == "CharSet")
1123                                                         charset = (CharSet) c.GetValue ();
1124                                                 else if (member_name == "EntryPoint")
1125                                                         entry_point = (string) c.GetValue ();
1126                                                 else if (member_name == "SetLastError")
1127                                                         set_last_err = (bool) c.GetValue ();
1128 #if FIXME
1129                                                 else if (member_name == "ExactSpelling")
1130                                                         exact_spelling = (bool) c.GetValue ();
1131 #endif
1132                                                 else if (member_name == "PreserveSig")
1133                                                         preserve_sig = (bool) c.GetValue ();
1134                                         } else { 
1135                                                 Error_AttributeArgumentNotValid (Location);
1136                                                 return null;
1137                                         }
1138                                         
1139                                 }
1140                         }
1141
1142                         if (entry_point == null)
1143                                 entry_point = name;
1144                         if (set_last_err)
1145                                 charset = (CharSet)((int)charset | 0x40);
1146                         
1147                         MethodBuilder mb = builder.DefinePInvokeMethod (
1148                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
1149                                 CallingConventions.Standard,
1150                                 ret_type,
1151                                 param_types,
1152                                 cc,
1153                                 charset);
1154
1155                         if (preserve_sig)
1156                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
1157                         
1158                         return mb;
1159                 }
1160                 
1161         }
1162         
1163         public class AttributeSection {
1164                 public readonly string    Target;
1165                 public readonly ArrayList Attributes;
1166                 
1167                 public AttributeSection (string target, ArrayList attrs)
1168                 {
1169                         Target = target;
1170                         Attributes = attrs;
1171                 }
1172                 
1173         }
1174
1175         public class Attributes {
1176                 public ArrayList AttributeSections;
1177
1178                 public Attributes (AttributeSection a)
1179                 {
1180                         AttributeSections = new ArrayList ();
1181                         AttributeSections.Add (a);
1182
1183                 }
1184
1185                 public void AddAttributeSection (AttributeSection a)
1186                 {
1187                         if (a != null && !AttributeSections.Contains (a))
1188                                 AttributeSections.Add (a);
1189                 }
1190
1191                 public bool Contains (Type t)
1192                 {
1193                         foreach (AttributeSection attr_section in AttributeSections){
1194                                 foreach (Attribute a in attr_section.Attributes){
1195                                         if (a.Type == t)
1196                                                 return true;
1197                                 }
1198                         }
1199                         
1200                         return false;
1201                 }
1202         }
1203 }