svn path=/trunk/mcs/; revision=60765
[mono.git] / mcs / mbas / 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.Collections.Specialized;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.InteropServices;
19 using System.Runtime.CompilerServices;
20 using System.Text;
21 using System.Text.RegularExpressions;
22 namespace Mono.MonoBASIC {
23
24         /// <summary>
25         ///   Base class for objects that can have Attributes applied to them.
26         /// </summary>
27         public abstract class Attributable {
28                 /// <summary>
29                 ///   Attributes for this type
30                 /// </summary>
31                 Attributes attributes;
32
33                 public Attributable(Attributes attrs)
34                 {
35                         attributes = attrs;
36                 }
37
38                 public Attributes OptAttributes 
39                 {
40                         get {
41                                 return attributes;
42                         }
43                         set {
44                                 attributes = value;
45                         }
46                 }
47
48                 /// <summary>
49                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
50                 /// </summary>
51                 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
52                 /// <summary>
53                 /// Returns one AttributeTarget for this element.
54                 /// </summary>
55                 public abstract AttributeTargets AttributeTargets { get; }
56         };
57         public class Attribute {
58                 public readonly string ExplicitTarget;
59                 public readonly string    Name;
60                 
61                 public readonly ArrayList Arguments;
62
63                 public Location Location;
64
65                 public Type Type;
66
67                 // Is non-null if type is AttributeUsageAttribute
68                 AttributeUsageAttribute usage_attribute;
69
70                 public AttributeUsageAttribute UsageAttribute {
71                         get {
72                                 return usage_attribute;
73                         }
74                 }
75                 
76                 bool usage_attr = false;
77                 
78                 MethodImplOptions ImplOptions;
79                 public UnmanagedType     UnmanagedType;
80                 CustomAttributeBuilder cb;
81
82                 public Attribute (string name, ArrayList args, Location loc)
83                 {
84                         Name = name;
85                         Arguments = args;
86                         Location = loc;
87                 }
88         
89                 public Attribute (string target, string name, ArrayList args, Location loc) 
90                 {
91                         ExplicitTarget = target;
92                         Object myObject;
93                         if (name=="AssemblyVersion")
94                         for (int i=0;i<args.Count;i++)
95                                 {
96                                 myObject=args[i];
97                                 
98                                         ArrayList arrList=(ArrayList)myObject;
99                                         for (int j=0;j<arrList.Count;j++)
100                                                 {
101                                                 
102                                                 Argument arg = (Argument)arrList[i];
103                                                 string strVersion = Regex.Replace(arg.Expr.ToString(),"StringLiteral","");
104                                                 strVersion = Regex.Replace(strVersion,@"\(|\)","");
105                                                 
106                                                 //Version = new Version(strVersion); it does not work. but it should
107                                                 //Making an ArrayList of integer to instatiate a new Version
108                                                 for(int cont=0; cont<strVersion.Length;cont++)
109                                                         if (Regex.IsMatch(strVersion[cont].ToString(),@"\d"))
110                                                         {
111                                                                 
112                                                                 CodeGen.ArrListVersion.Add(Convert.ToInt32(strVersion[cont].ToString()));
113                                                                 
114                                                         }//for
115                                                 
116                                                 }//for
117                                 }//for
118                         
119                 }
120
121                 void Error_InvalidNamedArgument (string name)
122                 {
123                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
124                                       "argument. Named attribute arguments must be fields which are not " +
125                                       "readonly, static or const, or properties with a set accessor which "+
126                                       "are not static.");
127                 }
128
129                 void Error_AttributeArgumentNotValid ()
130                 {
131                         Report.Error (182, Location,
132                                       "An attribute argument must be a constant expression, typeof " +
133                                       "expression or array creation expression");
134                 }
135
136                 static void Error_AttributeConstructorMismatch (Location loc)
137                 {
138                         Report.Error (
139                                         -6, loc,
140                                         "Could not find a constructor for this argument list.");
141                 }
142                 
143                 private Type CheckAttributeType (EmitContext ec) {
144                         Type t;
145                         bool isattributeclass = true;
146                         
147                         t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
148                         if (t != null) {
149                                 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
150                                 if (isattributeclass)
151                                         return t;
152                         }
153                         t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
154                         if (t != null) {
155                                 if (t.IsSubclassOf (TypeManager.attribute_type))
156                                         return t;
157                         }
158                         if (!isattributeclass) {
159                                 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
160                                 return null;
161                         }
162                         if (t != null) {
163                                 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
164                                 return null;
165                         }
166                         Report.Error (
167                                 246, Location, "Could not find attribute '" + Name + "' (are you" +
168                                 " missing a using directive or an assembly reference ?)");
169                         return null;
170                 }
171                 
172
173                 public Type ResolveType (EmitContext ec)
174                 {
175                         Type = CheckAttributeType (ec);
176                         return Type;
177                 }
178
179                 
180                 public CustomAttributeBuilder Resolve (EmitContext ec)
181                 {
182                         if (Type == null)
183                                 Type = CheckAttributeType (ec);
184                         if (Type == null)
185                                 return null;
186
187                         bool MethodImplAttr = false;
188                         bool MarshalAsAttr = false;
189
190                         usage_attr = false;
191
192                         if (Type == TypeManager.attribute_usage_type)
193                                 usage_attr = true;
194                         if (Type == TypeManager.methodimpl_attr_type)
195                                 MethodImplAttr = true;
196                         if (Type == TypeManager.marshal_as_attr_type)
197                                 MarshalAsAttr = true;
198
199                         // Now we extract the positional and named arguments
200                         
201                         ArrayList pos_args = new ArrayList ();
202                         ArrayList named_args = new ArrayList ();
203                         int pos_arg_count = 0;
204                         
205                         if (Arguments != null) {
206                                 pos_args = (ArrayList) Arguments [0];
207                                 if (pos_args != null)
208                                         pos_arg_count = pos_args.Count;
209                                 if (Arguments.Count > 1)
210                                         named_args = (ArrayList) Arguments [1];
211                         }
212
213                         object [] pos_values = new object [pos_arg_count];
214
215                         //
216                         // First process positional arguments 
217                         //
218
219                         int i;
220                         for (i = 0; i < pos_arg_count; i++) {
221                                 Argument a = (Argument) pos_args [i];
222                                 Expression e;
223
224                                 if (!a.Resolve (ec, Location))
225                                         return null;
226
227                                 e = a.Expr;
228
229                                 if (e is Constant) {
230                                         pos_values [i] = ((Constant) e).GetValue ();
231                                 } else if (e is TypeOf) {
232                                         pos_values [i] = ((TypeOf) e).TypeArg;
233                                 } else {
234                                         Error_AttributeArgumentNotValid ();
235                                         return null;
236                                 }
237                                 
238                                 if (usage_attr)
239                                         usage_attribute = new AttributeUsageAttribute ((AttributeTargets) pos_values [0]);
240                                 
241                                 if (MethodImplAttr)
242                                         this.ImplOptions = (MethodImplOptions) pos_values [0];
243                                 
244                                 if (MarshalAsAttr)
245                                         this.UnmanagedType =
246                                         (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
247                         }
248
249                         //
250                         // Now process named arguments
251                         //
252
253                         ArrayList field_infos = new ArrayList ();
254                         ArrayList prop_infos  = new ArrayList ();
255                         ArrayList field_values = new ArrayList ();
256                         ArrayList prop_values = new ArrayList ();
257                         
258                         for (i = 0; i < named_args.Count; i++) {
259                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
260                                 string member_name = (string) de.Key;
261                                 Argument a  = (Argument) de.Value;
262                                 Expression e;
263                                 
264                                 if (!a.Resolve (ec, Location))
265                                         return null;
266
267                                 Expression member = Expression.MemberLookup (
268                                         ec, Type, member_name,
269                                         MemberTypes.Field | MemberTypes.Property,
270                                         BindingFlags.Public | BindingFlags.Instance,
271                                         Location);
272
273                                 if (member == null || !(member is PropertyGroupExpr || member is FieldExpr)) {
274                                         Error_InvalidNamedArgument (member_name);
275                                         return null;
276                                 }
277
278                                 e = a.Expr;
279                                 if (member is PropertyGroupExpr) {
280                                         PropertyGroupExpr pe = (PropertyGroupExpr) member;
281                                         PropertyInfo pi = null;
282                                         if (pe.Properties.Length == 1) 
283                                                 pi = pe.Properties [0];
284                                         else {
285                                                 // find a property which doesnt take any arguments
286                                                 // Might be wrong, but this is just a temporary work-around
287                                                 foreach (PropertyInfo p in pe.Properties) {
288                                                         MethodInfo mi = p.GetGetMethod ();
289                                                         if (mi.GetParameters().Length == 0) {
290                                                                 pi = p;
291                                                                 break;
292                                                         }
293                                                 }
294                                         }
295
296                                         if (!pi.CanWrite) {
297                                                 Error_InvalidNamedArgument (member_name);
298                                                 return null;
299                                         }
300
301                                         if (e is Constant) {
302                                                 object o = ((Constant) e).GetValue ();
303                                                 prop_values.Add (o);
304                                                 
305                                                 if (usage_attr) {
306                                                         if (member_name == "AllowMultiple")
307                                                                 usage_attribute.AllowMultiple = (bool) o;
308                                                         if (member_name == "Inherited")
309                                                                 usage_attribute.Inherited = (bool) o;
310                                                 }
311                                                 
312                                         } else if (e is TypeOf) {
313                                                 prop_values.Add (((TypeOf) e).TypeArg);
314                                         } else {
315                                                 Error_AttributeArgumentNotValid ();
316                                                 return null;
317                                         }
318                                         
319                                         prop_infos.Add (pi);
320                                         
321                                 } else if (member is FieldExpr) {
322                                         FieldExpr fe = (FieldExpr) member;
323                                         FieldInfo fi = fe.FieldInfo;
324
325                                         if (fi.IsInitOnly) {
326                                                 Error_InvalidNamedArgument (member_name);
327                                                 return null;
328                                         }
329
330                                         //
331                                         // Handle charset here, and set the TypeAttributes
332                                         
333                                         if (e is Constant){
334                                                 object value = ((Constant) e).GetValue ();
335                                                 
336                                                 field_values.Add (value);
337                                         } else if (e is TypeOf) {
338                                                 field_values.Add (((TypeOf) e).TypeArg);
339                                         } else {
340                                                 Error_AttributeArgumentNotValid ();
341                                                 return null;
342                                         }
343                                         
344                                         field_infos.Add (fi);
345                                 }
346                         }
347
348                         Expression mg = Expression.MemberLookup (
349                                 ec, Type, ".ctor", MemberTypes.Constructor,
350                                 BindingFlags.Public | BindingFlags.Instance, Location);
351
352                         if (mg == null) {
353                                 Error_AttributeConstructorMismatch (Location);
354                                 return null;
355                         }
356
357                         MethodBase constructor = Invocation.OverloadResolve (
358                                 ec, (MethodGroupExpr) mg, pos_args, Location);
359
360                         if (constructor == null) {
361                                 Error_AttributeConstructorMismatch (Location);
362                                 return null;
363                         }
364
365                         //
366                         // Now we perform some checks on the positional args as they
367                         // cannot be null for a constructor which expects a parameter
368                         // of type object
369                         //
370
371                         ParameterData pd = Invocation.GetParameterData (constructor);
372
373                         for (int j = 0; j < pos_arg_count; ++j) {
374                                 Argument a = (Argument) pos_args [j];
375                                 
376                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
377                                         Error_AttributeArgumentNotValid ();
378                                         return null;
379                                 }
380                         }
381                         
382                         PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
383                         FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
384                         object [] field_values_arr = new object [field_values.Count];
385                         object [] prop_values_arr = new object [prop_values.Count];
386
387                         field_infos.CopyTo  (field_info_arr, 0);
388                         field_values.CopyTo (field_values_arr, 0);
389
390                         prop_values.CopyTo  (prop_values_arr, 0);
391                         prop_infos.CopyTo   (prop_info_arr, 0);
392
393                         try {
394                         
395                                 cb = new CustomAttributeBuilder (
396                                         (ConstructorInfo) constructor, pos_values,
397                                         prop_info_arr, prop_values_arr,
398                                         field_info_arr, field_values_arr); 
399                                 
400                         } catch (NullReferenceException) {
401                                 // 
402                                 // Don't know what to do here
403                                 //
404                         } catch {
405                                 //
406                                 // Sample:
407                                 // using System.ComponentModel;
408                                 // [DefaultValue (CollectionChangeAction.Add)]
409                                 // class X { static void Main () {} }
410                                 //
411                                 Report.Warning (
412                                         -23, Location,
413                                         "The compiler can not encode this attribute in .NET due to\n" +
414                                         "\ta bug in the .NET runtime.  Try the Mono runtime");
415                         }
416                         
417                         return cb;
418                 }
419
420                 public string GetValidTargets ()
421                 {
422                         StringBuilder sb = new StringBuilder ();
423                         AttributeTargets targets = GetAttributeUsage ().ValidOn;
424                         
425                         if ((targets & AttributeTargets.Assembly) != 0)
426                                 sb.Append ("'assembly' ");
427
428                         if ((targets & AttributeTargets.Class) != 0)
429                                 sb.Append ("'class' ");
430
431                         if ((targets & AttributeTargets.Constructor) != 0)
432                                 sb.Append ("'constructor' ");
433
434                         if ((targets & AttributeTargets.Delegate) != 0)
435                                 sb.Append ("'delegate' ");
436
437                         if ((targets & AttributeTargets.Enum) != 0)
438                                 sb.Append ("'enum' ");
439
440                         if ((targets & AttributeTargets.Event) != 0)
441                                 sb.Append ("'event' ");
442
443                         if ((targets & AttributeTargets.Field) != 0)
444                                 sb.Append ("'field' ");
445
446                         if ((targets & AttributeTargets.Interface) != 0)
447                                 sb.Append ("'interface' ");
448
449                         if ((targets & AttributeTargets.Method) != 0)
450                                 sb.Append ("'method' ");
451
452                         if ((targets & AttributeTargets.Module) != 0)
453                                 sb.Append ("'module' ");
454
455                         if ((targets & AttributeTargets.Parameter) != 0)
456                                 sb.Append ("'parameter' ");
457
458                         if ((targets & AttributeTargets.Property) != 0)
459                                 sb.Append ("'property' ");
460
461                         if ((targets & AttributeTargets.ReturnValue) != 0)
462                                 sb.Append ("'return value' ");
463
464                         if ((targets & AttributeTargets.Struct) != 0)
465                                 sb.Append ("'struct' ");
466
467                         return sb.ToString ();
468
469                 }
470
471                 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
472                 {
473                         Report.Error (
474                                 30662, loc, "Attribute '" + a.Name +
475                                 "' is not valid on this declaration type. " +
476                                 "It is valid on " + a.GetValidTargets () + "declarations only.");
477                 }
478
479                 public static bool CheckAttribute (Attribute a, object element)
480                 {
481                         //TypeContainer attr = TypeManager.LookupClass (a.Type);
482                         AttributeTargets targets = a.GetAttributeUsage ().ValidOn;
483
484
485                         if (element is Class) {
486                                 if ((targets & AttributeTargets.Class) != 0)
487                                         return true;
488                                 else
489                                         return false;
490                                 
491                         } else if (element is Struct) {
492                                 if ((targets & AttributeTargets.Struct) != 0)
493                                         return true;
494                                 else
495                                         return false;
496                         } else if (element is Constructor) {
497                                 if ((targets & AttributeTargets.Constructor) != 0)
498                                         return true;
499                                 else
500                                         return false;
501                         } else if (element is Delegate) {
502                                 if ((targets & AttributeTargets.Delegate) != 0)
503                                         return true;
504                                 else
505                                         return false;
506                         } else if (element is Enum) {
507                                 if ((targets & AttributeTargets.Enum) != 0)
508                                         return true;
509                                 else
510                                         return false;
511                         } else if (element is Event /*|| element is InterfaceEvent*/) {
512                                 if ((targets & AttributeTargets.Event) != 0)
513                                         return true;
514                                 else
515                                         return false;
516                         } else if (element is Field || element is FieldBuilder) {
517                                 if ((targets & AttributeTargets.Field) != 0)
518                                         return true;
519                                 else
520                                         return false;
521                         } else if (element is Interface) {
522                                 if ((targets & AttributeTargets.Interface) != 0)
523                                         return true;
524                                 else
525                                         return false;
526                         } else if (element is Method || element is Accessor) {
527                                 if ((targets & AttributeTargets.Method) != 0)
528                                         return true;
529                                 else
530                                         return false;
531                         } else if (element is ParameterBuilder) {
532                                 if ((targets & AttributeTargets.Parameter) != 0)
533                                         return true;
534                                 else
535                                         return false;
536                         } else if (element is Property /* || element is Indexer ||
537                                    element is InterfaceProperty || element is InterfaceIndexer*/) {
538                                 if ((targets & AttributeTargets.Property) != 0)
539                                         return true;
540                                 else
541                                         return false;
542                         } else if (element is AssemblyBuilder){
543                                 if ((targets & AttributeTargets.Assembly) != 0)
544                                         return true;
545                                 else
546                                         return false;
547                         } else if (element is ModuleBuilder){
548                                         if ((targets & AttributeTargets.Module) != 0)
549                                                 return true;
550                                         else
551                                                 return false;
552                                 }  
553
554                         return false;
555                 }
556
557                 /// <summary>
558                 /// Returns AttributeUsage attribute for this type
559                 /// </summary>
560                 public AttributeUsageAttribute GetAttributeUsage ()
561                 {
562                         Class attr_class = (Class) TypeManager.LookupClass (Type);
563
564                         if (attr_class == null) {
565                                 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
566                                 return (AttributeUsageAttribute)usage_attr [0];
567                         }
568                 
569                         return attr_class.AttributeUsage;
570                 }
571
572                 //
573                 // This method should be invoked to pull the DefaultPropName attribute from an
574                 // Indexer if it exists.
575                 //
576                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
577                 {
578                         if (opt_attrs == null)
579                                 return null;
580
581                         foreach (Attribute a in opt_attrs.Attrs) {
582                                 if (a.ResolveType (ec) == null)
583                                         return null;
584                                         
585                                 if (a.Type != TypeManager.indexer_name_type)
586                                         continue;
587
588                                 //
589                                 // So we have found an DefaultPropName, pull the data out.
590                                 //
591                                 if (a.Arguments == null || a.Arguments [0] == null){
592                                         Error_AttributeConstructorMismatch (a.Location);
593                                         return null;
594                                 }
595                                 ArrayList pos_args = (ArrayList) a.Arguments [0];
596                                 if (pos_args.Count == 0){
597                                         Error_AttributeConstructorMismatch (a.Location);
598                                         return null;
599                                 }
600                                         
601                                 Argument arg = (Argument) pos_args [0];
602                                 if (!arg.Resolve (ec, a.Location))
603                                         return null;
604                                         
605                                 Expression e = arg.Expr;
606                                 if (!(e is StringConstant)){
607                                         Error_AttributeConstructorMismatch (a.Location);
608                                         return null;
609                                 }
610
611                                 //
612                                 // Remove the attribute from the list
613                                 //
614                                 opt_attrs.Attrs.Remove (a);
615
616                                 return (((StringConstant) e).Value);
617                         }
618                         return null;
619                 }
620
621                 //
622                 // This pulls the condition name out of a Conditional attribute
623                 //
624                 public string Conditional_GetConditionName ()
625                 {
626                         //
627                         // So we have a Conditional, pull the data out.
628                         //
629                         if (Arguments == null || Arguments [0] == null){
630                                 Error_AttributeConstructorMismatch (Location);
631                                 return null;
632                         }
633
634                         ArrayList pos_args = (ArrayList) Arguments [0];
635                         if (pos_args.Count != 1){
636                                 Error_AttributeConstructorMismatch (Location);
637                                 return null;
638                         }
639
640                         Argument arg = (Argument) pos_args [0]; 
641                         if (!(arg.Expr is StringConstant)){
642                                 Error_AttributeConstructorMismatch (Location);
643                                 return null;
644                         }
645
646                         return ((StringConstant) arg.Expr).Value;
647                 }
648
649                 //
650                 // This pulls the obsolete message and error flag out of an Obsolete attribute
651                 //
652                 public string Obsolete_GetObsoleteMessage (out bool is_error)
653                 {
654                         is_error = false;
655                         //
656                         // So we have an Obsolete, pull the data out.
657                         //
658                         if (Arguments == null || Arguments [0] == null)
659                                 return "";
660
661                         ArrayList pos_args = (ArrayList) Arguments [0];
662                         if (pos_args.Count == 0)
663                                 return "";
664                         else if (pos_args.Count > 2){
665                                 Error_AttributeConstructorMismatch (Location);
666                                 return null;
667                         }
668
669                         Argument arg = (Argument) pos_args [0]; 
670                         if (!(arg.Expr is StringConstant)){
671                                 Error_AttributeConstructorMismatch (Location);
672                                 return null;
673                         }
674
675                         if (pos_args.Count == 2){
676                                 Argument arg2 = (Argument) pos_args [1];
677                                 if (!(arg2.Expr is BoolConstant)){
678                                         Error_AttributeConstructorMismatch (Location);
679                                         return null;
680                                 }
681                                 is_error = ((BoolConstant) arg2.Expr).Value;
682                         }
683
684                         return ((StringConstant) arg.Expr).Value;
685                 }
686
687                 
688                 /// <summary>
689                 /// Emit attribute for Attributable symbol
690                 /// </summary>
691                 public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr)
692                 {
693                         CustomAttributeBuilder cb = Resolve (ec);
694                         if (cb == null)
695                                 return;
696                 
697                         AttributeUsageAttribute usage_attr = GetAttributeUsage ();
698                         if ((usage_attr.ValidOn & ias.AttributeTargets) == 0) {
699                                 Report.Error (30662, Location, "Attribute" + Name + "is not valid on this declaration type. It is valid on " + GetValidTargets () + " declarations only.");
700                                 return;
701                         }
702                 
703                         ias.ApplyAttributeBuilder (this, cb);
704                 }
705
706                 //
707                 // Applies the attributes to the `builder'.
708                 //                                                                      
709                 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
710                                                     Attributes opt_attrs, Location loc)
711                 {
712                         if (opt_attrs == null)
713                                 return;
714
715                         foreach (Attribute a in opt_attrs.Attrs) {
716                                 CustomAttributeBuilder cb = a.Resolve (ec);
717
718                                 if (cb == null)
719                                         continue;
720
721                                 if (!(kind is TypeContainer))
722                                         if (!CheckAttribute (a, kind)) {
723                                                         Error_AttributeNotValidForElement (a, loc);
724                                                         return;
725                                         }
726
727                                 if (kind is Method || kind is Accessor) {
728                                         if (a.Type == TypeManager.methodimpl_attr_type) {
729                                                 if (a.ImplOptions == MethodImplOptions.InternalCall)
730                                                                 ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall |   MethodImplAttributes.Runtime);
731                                         } else if (a.Type != TypeManager.dllimport_type){
732                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);
733                                         }
734                                 }  else
735                                         throw new Exception ("Unknown kind: " + kind);
736                         }
737                 }
738
739                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
740                                                           MethodAttributes flags, Type ret_type, Type [] param_types)
741                 {
742                         //
743                         // We extract from the attribute the information we need 
744                         //
745
746                         if (Arguments == null) {
747                                 Console.WriteLine ("Internal error : this is not supposed to happen !");
748                                 return null;
749                         }
750
751                         Type = CheckAttributeType (ec);
752                         if (Type == null)
753                                 return null;
754                         
755                         ArrayList named_args = new ArrayList ();
756                         
757                         ArrayList pos_args = (ArrayList) Arguments [0];
758                         if (Arguments.Count > 1)
759                                 named_args = (ArrayList) Arguments [1];
760                         
761
762                         string dll_name = null;
763                         
764                         Argument tmp = (Argument) pos_args [0];
765
766                         if (!tmp.Resolve (ec, Location))
767                                 return null;
768                         
769                         if (tmp.Expr is Constant)
770                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
771                         else { 
772                                 Error_AttributeArgumentNotValid ();
773                                 return null;
774                         }
775
776                         // Now we process the named arguments
777                         CallingConvention cc = CallingConvention.Winapi;
778                         CharSet charset = CharSet.Ansi;
779                         bool preserve_sig = true;
780                         /*bool exact_spelling = false;
781                         bool set_last_err = false;*/
782                         string entry_point = null;
783
784                         for (int i = 0; i < named_args.Count; i++) {
785
786                                 DictionaryEntry de = (DictionaryEntry) named_args [i];
787
788                                 string member_name = (string) de.Key;
789                                 Argument a  = (Argument) de.Value;
790
791                                 if (!a.Resolve (ec, Location))
792                                         return null;
793
794                                 Expression member = Expression.MemberLookup (
795                                         ec, Type, member_name, 
796                                         MemberTypes.Field | MemberTypes.Property,
797                                         BindingFlags.Public | BindingFlags.Instance,
798                                         Location);
799
800                                 if (member == null || !(member is FieldExpr)) {
801                                         Error_InvalidNamedArgument (member_name);
802                                         return null;
803                                 }
804
805                                 if (member is FieldExpr) {
806                                         FieldExpr fe = (FieldExpr) member;
807                                         FieldInfo fi = fe.FieldInfo;
808
809                                         if (fi.IsInitOnly) {
810                                                 Error_InvalidNamedArgument (member_name);
811                                                 return null;
812                                         }
813
814                                         if (a.Expr is Constant) {
815                                                 Constant c = (Constant) a.Expr;
816                                                 
817                                                 if (member_name == "CallingConvention")
818                                                         cc = (CallingConvention) c.GetValue ();
819                                                 else if (member_name == "CharSet")
820                                                         charset = (CharSet) c.GetValue ();
821                                                 else if (member_name == "EntryPoint")
822                                                         entry_point = (string) c.GetValue ();
823                                                 /*else if (member_name == "SetLastError")
824                                                         set_last_err = (bool) c.GetValue ();
825                                                 else if (member_name == "ExactSpelling")
826                                                         exact_spelling = (bool) c.GetValue ();*/
827                                                 else if (member_name == "PreserveSig")
828                                                         preserve_sig = (bool) c.GetValue ();
829                                         } else { 
830                                                 Error_AttributeArgumentNotValid ();
831                                                 return null;
832                                         }
833                                         
834                                 }
835                         }
836
837                         if (entry_point == null)
838                                 entry_point = name;
839                         
840                         MethodBuilder mb = builder.DefinePInvokeMethod (
841                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
842                                 CallingConventions.Standard,
843                                 ret_type,
844                                 param_types,
845                                 cc,
846                                 charset);
847
848                         if (preserve_sig)
849                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
850                         
851                         return mb;
852                 }
853
854                 public bool IsAssemblyAttribute {
855                         get {
856                                 return ExplicitTarget == "assembly";
857                         }
858                 }
859
860                 public bool IsModuleAttribute {
861                         get {
862                                 return ExplicitTarget == "module";
863                         }
864                 }
865         }
866         
867         public class Attributes {
868                 public ArrayList Attrs;
869                 public Location Location;
870                 
871                 public Attributes (Attribute a)
872                 {
873                         Attrs = new ArrayList ();
874                         Attrs.Add (a);
875                 }
876
877                 public Attributes (ArrayList attrs)
878                 {
879                         Attrs = attrs;
880                 }
881
882                 public void Add (Attribute attr)
883                 {
884                         Attrs.Add (attr);
885                 }
886
887                 public void Add (ArrayList attrs)
888                 {
889                         Attrs.AddRange (attrs);
890                 }
891
892                 public void Emit (EmitContext ec, Attributable ias)
893                 {
894                         ListDictionary ld = new ListDictionary ();
895         
896                         foreach (Attribute a in Attrs)
897                                 a.Emit (ec, ias, ld);
898                 }
899         }
900 }
901
902