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