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