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