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