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