2004-02-14 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
[mono.git] / mcs / gmcs / 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 an AttributeUsage attribute\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                 // non-null if named args present after Resolve () is called\r
46                 PropertyInfo [] prop_info_arr;\r
47                 FieldInfo [] field_info_arr;\r
48                 object [] field_values_arr;\r
49                 object [] prop_values_arr;\r
50                 \r
51                 public Attribute (string name, ArrayList args, Location loc)\r
52                 {\r
53                         Name = name;\r
54                         Arguments = args;\r
55                         Location = loc;\r
56                 }\r
57 \r
58                 void Error_InvalidNamedArgument (string name)\r
59                 {\r
60                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +\r
61                                       "argument. Named attribute arguments must be fields which are not " +\r
62                                       "readonly, static or const, or properties with a set accessor which "+\r
63                                       "are not static.");\r
64                 }\r
65 \r
66                 static void Error_AttributeArgumentNotValid (Location loc)\r
67                 {\r
68                         Report.Error (182, loc,\r
69                                       "An attribute argument must be a constant expression, typeof " +\r
70                                       "expression or array creation expression");\r
71                 }\r
72 \r
73                 static void Error_AttributeConstructorMismatch (Location loc)\r
74                 {\r
75                         Report.Error (-6, loc,\r
76                                       "Could not find a constructor for this argument list.");\r
77                 }\r
78 \r
79                 static void Error_TypeParameterInAttribute (Location loc)\r
80                 {\r
81                         Report.Error (\r
82                                 -202, loc, "Can not use a type parameter in an attribute");\r
83                 }\r
84 \r
85                 /// <summary>\r
86                 ///   Tries to resolve the type of the attribute. Flags an error if it can't.\r
87                 /// </summary>\r
88                 private Type CheckAttributeType (EmitContext ec) {\r
89                         Type t;\r
90                         bool isattributeclass = true;\r
91                         \r
92                         t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);\r
93                         if (t != null) {\r
94                                 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);\r
95                                 if (isattributeclass)\r
96                                         return t;\r
97                         }\r
98                         t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);\r
99                         if (t != null) {\r
100                                 if (t.IsSubclassOf (TypeManager.attribute_type))\r
101                                         return t;\r
102                         }\r
103                         if (!isattributeclass) {\r
104                                 Report.Error (616, Location, "'" + Name + "': is not an attribute class");\r
105                                 return null;\r
106                         }\r
107                         if (t != null) {\r
108                                 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");\r
109                                 return null;\r
110                         }\r
111                         Report.Error (\r
112                                 246, Location, "Could not find attribute '" + Name + "' (are you" +\r
113                                 " missing a using directive or an assembly reference ?)");\r
114                         return null;\r
115                 }\r
116 \r
117                 public Type ResolveType (EmitContext ec)\r
118                 {\r
119                         Type = CheckAttributeType (ec);\r
120                         return Type;\r
121                 }\r
122 \r
123                 /// <summary>\r
124                 ///   Validates the guid string\r
125                 /// </summary>\r
126                 bool ValidateGuid (string guid)\r
127                 {\r
128                         try {\r
129                                 new Guid (guid);\r
130                                 return true;\r
131                         } catch {\r
132                                 Report.Error (647, Location, "Format of GUID is invalid: " + guid);\r
133                                 return false;\r
134                         }\r
135                 }\r
136 \r
137                 //\r
138                 // Given an expression, if the expression is a valid attribute-argument-expression\r
139                 // returns an object that can be used to encode it, or null on failure.\r
140                 //\r
141                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)\r
142                 {\r
143                         if (e is Constant) {\r
144                                 result = ((Constant) e).GetValue ();\r
145                                 return true;\r
146                         } else if (e is TypeOf) {\r
147                                 result = ((TypeOf) e).TypeArg;\r
148                                 return true;\r
149                         } else if (e is ArrayCreation){\r
150                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();\r
151                                 if (result != null)\r
152                                         return true;\r
153                         } else if (e is EmptyCast) {\r
154                                 result = e;\r
155                                 if (((EmptyCast) e).Child is Constant) {\r
156                                         result = ((Constant) ((EmptyCast)e).Child).GetValue();\r
157                                 }\r
158                                 return true;\r
159                         }\r
160 \r
161                         result = null;\r
162                         Error_AttributeArgumentNotValid (loc);\r
163                         return false;\r
164                 }\r
165                 \r
166                 public CustomAttributeBuilder Resolve (EmitContext ec)\r
167                 {\r
168                         if (Type == null)\r
169                                 Type = CheckAttributeType (ec);\r
170                         if (Type == null)\r
171                                 return null;\r
172 \r
173                         bool MethodImplAttr = false;\r
174                         bool MarshalAsAttr = false;\r
175                         bool GuidAttr = false;\r
176                         UsageAttr = false;\r
177 \r
178                         bool DoCompares = true;\r
179 \r
180                         //\r
181                         // If we are a certain special attribute, we\r
182                         // set the information accordingly\r
183                         //\r
184                         \r
185                         if (Type == TypeManager.attribute_usage_type)\r
186                                 UsageAttr = true;\r
187                         else if (Type == TypeManager.methodimpl_attr_type)\r
188                                 MethodImplAttr = true;\r
189                         else if (Type == TypeManager.marshal_as_attr_type)\r
190                                 MarshalAsAttr = true;\r
191                         else if (Type == TypeManager.guid_attr_type)\r
192                                 GuidAttr = true;\r
193                         else\r
194                                 DoCompares = false;\r
195 \r
196                         // Now we extract the positional and named arguments\r
197                         \r
198                         ArrayList pos_args = new ArrayList ();\r
199                         ArrayList named_args = new ArrayList ();\r
200                         int pos_arg_count = 0;\r
201                         \r
202                         if (Arguments != null) {\r
203                                 pos_args = (ArrayList) Arguments [0];\r
204                                 if (pos_args != null)\r
205                                         pos_arg_count = pos_args.Count;\r
206                                 if (Arguments.Count > 1)\r
207                                         named_args = (ArrayList) Arguments [1];\r
208                         }\r
209 \r
210                         object [] pos_values = new object [pos_arg_count];\r
211 \r
212                         //\r
213                         // First process positional arguments \r
214                         //\r
215 \r
216                         int i;\r
217                         for (i = 0; i < pos_arg_count; i++) {\r
218                                 Argument a = (Argument) pos_args [i];\r
219                                 Expression e;\r
220 \r
221                                 if (!a.Resolve (ec, Location))\r
222                                         return null;\r
223 \r
224                                 e = a.Expr;\r
225 \r
226                                 object val;\r
227                                 if (!GetAttributeArgumentExpression (e, Location, out val))\r
228                                         return null;\r
229                                 \r
230                                 pos_values [i] = val;\r
231                                 if (DoCompares){\r
232                                         if (UsageAttr)\r
233                                                 this.Targets = (AttributeTargets) pos_values [0];\r
234                                         else if (MethodImplAttr)\r
235                                                 this.ImplOptions = (MethodImplOptions) pos_values [0];\r
236                                         else if (GuidAttr){\r
237                                                 //\r
238                                                 // we will later check the validity of the type\r
239                                                 //\r
240                                                 if (pos_values [0] is string){\r
241                                                         if (!ValidateGuid ((string) pos_values [0]))\r
242                                                                 return null;\r
243                                                 }\r
244                                                 \r
245                                         } else if (MarshalAsAttr)\r
246                                                 this.UnmanagedType =\r
247                                                 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];\r
248                                 }\r
249                         }\r
250 \r
251                         //\r
252                         // Now process named arguments\r
253                         //\r
254 \r
255                         ArrayList field_infos = null;\r
256                         ArrayList prop_infos  = null;\r
257                         ArrayList field_values = null;\r
258                         ArrayList prop_values = null;\r
259 \r
260                         if (named_args.Count > 0) {\r
261                                 field_infos = new ArrayList ();\r
262                                 prop_infos  = new ArrayList ();\r
263                                 field_values = new ArrayList ();\r
264                                 prop_values = new ArrayList ();\r
265                         }\r
266                         \r
267                         for (i = 0; i < named_args.Count; i++) {\r
268                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
269                                 string member_name = (string) de.Key;\r
270                                 Argument a  = (Argument) de.Value;\r
271                                 Expression e;\r
272                                 \r
273                                 if (!a.Resolve (ec, Location))\r
274                                         return null;\r
275 \r
276                                 Expression member = Expression.MemberLookup (\r
277                                         ec, Type, member_name,\r
278                                         MemberTypes.Field | MemberTypes.Property,\r
279                                         BindingFlags.Public | BindingFlags.Instance,\r
280                                         Location);\r
281 \r
282                                 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {\r
283                                         Error_InvalidNamedArgument (member_name);\r
284                                         return null;\r
285                                 }\r
286 \r
287                                 e = a.Expr;\r
288                                 if (e is TypeParameterExpr){\r
289                                         Error_TypeParameterInAttribute (Location);\r
290                                         return null;\r
291                                 }\r
292                                         \r
293                                 if (member is PropertyExpr) {\r
294                                         PropertyExpr pe = (PropertyExpr) member;\r
295                                         PropertyInfo pi = pe.PropertyInfo;\r
296 \r
297                                         if (!pi.CanWrite) {\r
298                                                 Error_InvalidNamedArgument (member_name);\r
299                                                 return null;\r
300                                         }\r
301 \r
302                                         if (e is Constant) {\r
303                                                 object o = ((Constant) e).GetValue ();\r
304                                                 prop_values.Add (o);\r
305                                                 \r
306                                                 if (UsageAttr) {\r
307                                                         if (member_name == "AllowMultiple")\r
308                                                                 this.AllowMultiple = (bool) o;\r
309                                                         if (member_name == "Inherited")\r
310                                                                 this.Inherited = (bool) o;\r
311                                                 }\r
312                                                 \r
313                                         } else if (e is TypeOf) {\r
314                                                 prop_values.Add (((TypeOf) e).TypeArg);\r
315                                         } else if (e is ArrayCreation) {\r
316                                                 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());\r
317                                         } else {\r
318                                                 Error_AttributeArgumentNotValid (Location);\r
319                                                 return null;\r
320                                         }\r
321                                         \r
322                                         prop_infos.Add (pi);\r
323                                         \r
324                                 } else if (member is FieldExpr) {\r
325                                         FieldExpr fe = (FieldExpr) member;\r
326                                         FieldInfo fi = fe.FieldInfo;\r
327 \r
328                                         if (fi.IsInitOnly) {\r
329                                                 Error_InvalidNamedArgument (member_name);\r
330                                                 return null;\r
331                                         }\r
332 \r
333                                         //\r
334                                         // Handle charset here, and set the TypeAttributes\r
335                                         \r
336                                         if (e is Constant){\r
337                                                 object value = ((Constant) e).GetValue ();\r
338                                                 \r
339                                                 field_values.Add (value);\r
340                                         } else if (e is TypeOf) {\r
341                                                 field_values.Add (((TypeOf) e).TypeArg);\r
342                                         } else {\r
343                                                 Error_AttributeArgumentNotValid (Location);\r
344                                                 return null;\r
345                                         }\r
346                                         \r
347                                         field_infos.Add (fi);\r
348                                 }\r
349                         }\r
350 \r
351                         Expression mg = Expression.MemberLookup (\r
352                                 ec, Type, ".ctor", MemberTypes.Constructor,\r
353                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,\r
354                                 Location);\r
355 \r
356                         if (mg == null) {\r
357                                 Error_AttributeConstructorMismatch (Location);\r
358                                 return null;\r
359                         }\r
360 \r
361                         MethodBase constructor = Invocation.OverloadResolve (\r
362                                 ec, (MethodGroupExpr) mg, pos_args, Location);\r
363 \r
364                         if (constructor == null) {\r
365                                 Error_AttributeConstructorMismatch (Location);\r
366                                 return null;\r
367                         }\r
368 \r
369                         //\r
370                         // Now we perform some checks on the positional args as they\r
371                         // cannot be null for a constructor which expects a parameter\r
372                         // of type object\r
373                         //\r
374 \r
375                         ParameterData pd = Invocation.GetParameterData (constructor);\r
376 \r
377                         int group_in_params_array = Int32.MaxValue;\r
378                         int pc = pd.Count;\r
379                         if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)\r
380                                 group_in_params_array = pc-1;\r
381                         \r
382                         for (int j = 0; j < pos_arg_count; ++j) {\r
383                                 Argument a = (Argument) pos_args [j];\r
384                                 \r
385                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {\r
386                                         Error_AttributeArgumentNotValid (Location);\r
387                                         return null;\r
388                                 }\r
389 \r
390                                 if (j < group_in_params_array)\r
391                                         continue;\r
392                                 \r
393                                 if (j == group_in_params_array){\r
394                                         object v = pos_values [j];\r
395                                         int count = pos_arg_count - j;\r
396 \r
397                                         object [] array = new object [count];\r
398                                         pos_values [j] = array;\r
399                                         array [0] = v;\r
400                                 } else {\r
401                                         object [] array = (object []) pos_values [group_in_params_array];\r
402 \r
403                                         array [j - group_in_params_array] = pos_values [j];\r
404                                 }\r
405                         }\r
406 \r
407                         //\r
408                         // Adjust the size of the pos_values if it had params\r
409                         //\r
410                         if (group_in_params_array != Int32.MaxValue){\r
411                                 int argc = group_in_params_array+1;\r
412                                 object [] new_pos_values = new object [argc];\r
413 \r
414                                 for (int p = 0; p < argc; p++)\r
415                                         new_pos_values [p] = pos_values [p];\r
416                                 pos_values = new_pos_values;\r
417                         }\r
418 \r
419                         try {\r
420                                 if (named_args.Count > 0) {\r
421                                         prop_info_arr = new PropertyInfo [prop_infos.Count];\r
422                                         field_info_arr = new FieldInfo [field_infos.Count];\r
423                                         field_values_arr = new object [field_values.Count];\r
424                                         prop_values_arr = new object [prop_values.Count];\r
425 \r
426                                         field_infos.CopyTo  (field_info_arr, 0);\r
427                                         field_values.CopyTo (field_values_arr, 0);\r
428 \r
429                                         prop_values.CopyTo  (prop_values_arr, 0);\r
430                                         prop_infos.CopyTo   (prop_info_arr, 0);\r
431 \r
432                                         cb = new CustomAttributeBuilder (\r
433                                                 (ConstructorInfo) constructor, pos_values,\r
434                                                 prop_info_arr, prop_values_arr,\r
435                                                 field_info_arr, field_values_arr);\r
436                                 }\r
437                                 else\r
438                                         cb = new CustomAttributeBuilder (\r
439                                                 (ConstructorInfo) constructor, pos_values);\r
440                         } catch (NullReferenceException) {\r
441                                 // \r
442                                 // Don't know what to do here\r
443                                 //\r
444                                 Report.Warning (\r
445                                         -101, Location, "NullReferenceException while trying to create attribute." +\r
446                                         "Something's wrong!");\r
447                         } catch (Exception e) {\r
448                                 //\r
449                                 // Sample:\r
450                                 // using System.ComponentModel;\r
451                                 // [DefaultValue (CollectionChangeAction.Add)]\r
452                                 // class X { static void Main () {} }\r
453                                 //\r
454                                 Report.Warning (\r
455                                         -23, Location,\r
456                                         "The compiler can not encode this attribute in .NET due to\n" +\r
457                                         "\ta bug in the .NET runtime.  Try the Mono runtime.\nThe error was: " + e.Message);\r
458                         }\r
459                         \r
460                         return cb;\r
461                 }\r
462 \r
463                 /// <summary>\r
464                 ///   Get a string containing a list of valid targets for the attribute 'attr'\r
465                 /// </summary>\r
466                 static string GetValidTargets (Attribute attr)\r
467                 {\r
468                         StringBuilder sb = new StringBuilder ();\r
469                         AttributeTargets targets = 0;\r
470                         \r
471                         TypeContainer a = TypeManager.LookupAttr (attr.Type);\r
472 \r
473                         if (a == null) {\r
474                                 \r
475                                 System.Attribute [] attrs = null;\r
476                                 \r
477                                 try {\r
478                                         attrs = System.Attribute.GetCustomAttributes (attr.Type);\r
479                                         \r
480                                 } catch {\r
481                                         Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +\r
482                                                       " (maybe you forgot to set the usage using the" +\r
483                                                       " AttributeUsage attribute ?).");\r
484                                         return null;\r
485                                 }\r
486                                         \r
487                                 foreach (System.Attribute tmp in attrs)\r
488                                         if (tmp is AttributeUsageAttribute) {\r
489                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
490                                                 break;\r
491                                         }\r
492                         } else\r
493                                 targets = a.Targets;\r
494 \r
495                         \r
496                         if ((targets & AttributeTargets.Assembly) != 0)\r
497                                 sb.Append ("'assembly' ");\r
498 \r
499                         if ((targets & AttributeTargets.Class) != 0)\r
500                                 sb.Append ("'class' ");\r
501 \r
502                         if ((targets & AttributeTargets.Constructor) != 0)\r
503                                 sb.Append ("'constructor' ");\r
504 \r
505                         if ((targets & AttributeTargets.Delegate) != 0)\r
506                                 sb.Append ("'delegate' ");\r
507 \r
508                         if ((targets & AttributeTargets.Enum) != 0)\r
509                                 sb.Append ("'enum' ");\r
510 \r
511                         if ((targets & AttributeTargets.Event) != 0)\r
512                                 sb.Append ("'event' ");\r
513 \r
514                         if ((targets & AttributeTargets.Field) != 0)\r
515                                 sb.Append ("'field' ");\r
516 \r
517                         if ((targets & AttributeTargets.Interface) != 0)\r
518                                 sb.Append ("'interface' ");\r
519 \r
520                         if ((targets & AttributeTargets.Method) != 0)\r
521                                 sb.Append ("'method' ");\r
522 \r
523                         if ((targets & AttributeTargets.Module) != 0)\r
524                                 sb.Append ("'module' ");\r
525 \r
526                         if ((targets & AttributeTargets.Parameter) != 0)\r
527                                 sb.Append ("'parameter' ");\r
528 \r
529                         if ((targets & AttributeTargets.Property) != 0)\r
530                                 sb.Append ("'property' ");\r
531 \r
532                         if ((targets & AttributeTargets.ReturnValue) != 0)\r
533                                 sb.Append ("'return value' ");\r
534 \r
535                         if ((targets & AttributeTargets.Struct) != 0)\r
536                                 sb.Append ("'struct' ");\r
537 \r
538                         return sb.ToString ();\r
539 \r
540                 }\r
541 \r
542                 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)\r
543                 {\r
544                         Report.Error (\r
545                                 592, loc, "Attribute '" + a.Name +\r
546                                 "' is not valid on this declaration type. " +\r
547                                 "It is valid on " + GetValidTargets (a) + "declarations only.");\r
548                 }\r
549 \r
550                 /// <summary>\r
551                 ///   Ensure that Attribute 'a' is being applied to the right language element (target)\r
552                 /// </summary>\r
553                 public static bool CheckAttributeTarget (Attribute a, object element)\r
554                 {\r
555                         TypeContainer attr = TypeManager.LookupAttr (a.Type);\r
556                         AttributeTargets targets = 0;\r
557 \r
558                         if (attr == null) {\r
559                                 System.Attribute [] attrs = null;\r
560                                 \r
561                                 try {\r
562                                         attrs = System.Attribute.GetCustomAttributes (a.Type);\r
563 \r
564                                 } catch {\r
565                                         Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +\r
566                                                       " (maybe you forgot to set the usage using the" +\r
567                                                       " AttributeUsage attribute ?).");\r
568                                         return false;\r
569                                 }\r
570                                         \r
571                                 foreach (System.Attribute tmp in attrs)\r
572                                         if (tmp is AttributeUsageAttribute) { \r
573                                                 targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
574                                                 break;\r
575                                         }\r
576                         } else\r
577                                 targets = attr.Targets;\r
578 \r
579 \r
580                         if (element is Class) {\r
581                                 if ((targets & AttributeTargets.Class) != 0)\r
582                                         return true;\r
583                                 else\r
584                                         return false;\r
585                                 \r
586                         } else if (element is Struct) {\r
587                                 if ((targets & AttributeTargets.Struct) != 0)\r
588                                         return true;\r
589                                 else\r
590                                         return false;\r
591                         } else if (element is Constructor) {\r
592                                 if ((targets & AttributeTargets.Constructor) != 0)\r
593                                         return true;\r
594                                 else\r
595                                         return false;\r
596                         } else if (element is Delegate) {\r
597                                 if ((targets & AttributeTargets.Delegate) != 0)\r
598                                         return true;\r
599                                 else\r
600                                         return false;\r
601                         } else if (element is Enum) {\r
602                                 if ((targets & AttributeTargets.Enum) != 0)\r
603                                         return true;\r
604                                 else\r
605                                         return false;\r
606                         } else if (element is Event || element is InterfaceEvent) {\r
607                                 if ((targets & AttributeTargets.Event) != 0)\r
608                                         return true;\r
609                                 else\r
610                                         return false;\r
611                         } else if (element is Field || element is FieldBuilder) {\r
612                                 if ((targets & AttributeTargets.Field) != 0)\r
613                                         return true;\r
614                                 else\r
615                                         return false;\r
616                         } else if (element is Interface) {\r
617                                 if ((targets & AttributeTargets.Interface) != 0)\r
618                                         return true;\r
619                                 else\r
620                                         return false;\r
621                         } else if (element is Method || element is Operator ||\r
622                                    element is InterfaceMethod || element is Accessor) {\r
623                                 if ((targets & AttributeTargets.Method) != 0)\r
624                                         return true;\r
625                                 else\r
626                                         return false;\r
627                         } else if (element is ParameterBuilder) {\r
628                                 if ((targets & AttributeTargets.Parameter) != 0 ||\r
629                                     (targets & AttributeTargets.ReturnValue) != 0)\r
630                                         return true;\r
631                                 else\r
632                                         return false;\r
633                         } else if (element is Property || element is Indexer ||\r
634                                    element is InterfaceProperty || element is InterfaceIndexer) {\r
635                                 if ((targets & AttributeTargets.Property) != 0)\r
636                                         return true;\r
637                                 else\r
638                                         return false;\r
639                         } else if (element is AssemblyBuilder){\r
640                                 if ((targets & AttributeTargets.Assembly) != 0)\r
641                                         return true;\r
642                                 else\r
643                                         return false;\r
644                         }\r
645 \r
646                         return false;\r
647                 }\r
648 \r
649                 //\r
650                 // This method should be invoked to pull the IndexerName attribute from an\r
651                 // Indexer if it exists.\r
652                 //\r
653                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)\r
654                 {\r
655                         if (opt_attrs == null)\r
656                                 return null;\r
657                         if (opt_attrs.AttributeSections == null)\r
658                                 return null;\r
659 \r
660                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
661                                 if (asec.Attributes == null)\r
662                                         continue;\r
663 \r
664                                 foreach (Attribute a in asec.Attributes){\r
665                                         if (a.ResolveType (ec) == null)\r
666                                                 return null;\r
667 \r
668                                         if (a.Type != TypeManager.indexer_name_type)\r
669                                                 continue;\r
670 \r
671                                         //\r
672                                         // So we have found an IndexerName, pull the data out.\r
673                                         //\r
674                                         if (a.Arguments == null || a.Arguments [0] == null){\r
675                                                 Error_AttributeConstructorMismatch (a.Location);\r
676                                                 return null;\r
677                                         }\r
678                                         ArrayList pos_args = (ArrayList) a.Arguments [0];\r
679                                         if (pos_args.Count == 0){\r
680                                                 Error_AttributeConstructorMismatch (a.Location);\r
681                                                 return null;\r
682                                         }\r
683                                         \r
684                                         Argument arg = (Argument) pos_args [0];\r
685                                         if (!arg.Resolve (ec, a.Location))\r
686                                                 return null;\r
687                                         \r
688                                         Expression e = arg.Expr;\r
689                                         if (!(e is StringConstant)){\r
690                                                 Error_AttributeConstructorMismatch (a.Location);\r
691                                                 return null;\r
692                                         }\r
693 \r
694                                         //\r
695                                         // Remove the attribute from the list\r
696                                         //\r
697                                         asec.Attributes.Remove (a);\r
698 \r
699                                         return (((StringConstant) e).Value);\r
700                                 }\r
701                         }\r
702                         return null;\r
703                 }\r
704 \r
705                 //\r
706                 // This pulls the condition name out of a Conditional attribute\r
707                 //\r
708                 public string Conditional_GetConditionName ()\r
709                 {\r
710                         //\r
711                         // So we have a Conditional, pull the data out.\r
712                         //\r
713                         if (Arguments == null || Arguments [0] == null){\r
714                                 Error_AttributeConstructorMismatch (Location);\r
715                                 return null;\r
716                         }\r
717 \r
718                         ArrayList pos_args = (ArrayList) Arguments [0];\r
719                         if (pos_args.Count != 1){\r
720                                 Error_AttributeConstructorMismatch (Location);\r
721                                 return null;\r
722                         }\r
723 \r
724                         Argument arg = (Argument) pos_args [0]; \r
725                         if (!(arg.Expr is StringConstant)){\r
726                                 Error_AttributeConstructorMismatch (Location);\r
727                                 return null;\r
728                         }\r
729 \r
730                         return ((StringConstant) arg.Expr).Value;\r
731                 }\r
732 \r
733                 //\r
734                 // This pulls the obsolete message and error flag out of an Obsolete attribute\r
735                 //\r
736                 public string Obsolete_GetObsoleteMessage (out bool is_error)\r
737                 {\r
738                         is_error = false;\r
739                         //\r
740                         // So we have an Obsolete, pull the data out.\r
741                         //\r
742                         if (Arguments == null || Arguments [0] == null)\r
743                                 return "";\r
744 \r
745                         ArrayList pos_args = (ArrayList) Arguments [0];\r
746                         if (pos_args.Count == 0)\r
747                                 return "";\r
748                         else if (pos_args.Count > 2){\r
749                                 Error_AttributeConstructorMismatch (Location);\r
750                                 return null;\r
751                         }\r
752 \r
753                         Argument arg = (Argument) pos_args [0]; \r
754                         if (!(arg.Expr is StringConstant)){\r
755                                 Error_AttributeConstructorMismatch (Location);\r
756                                 return null;\r
757                         }\r
758 \r
759                         if (pos_args.Count == 2){\r
760                                 Argument arg2 = (Argument) pos_args [1];\r
761                                 if (!(arg2.Expr is BoolConstant)){\r
762                                         Error_AttributeConstructorMismatch (Location);\r
763                                         return null;\r
764                                 }\r
765                                 is_error = ((BoolConstant) arg2.Expr).Value;\r
766                         }\r
767 \r
768                         return ((StringConstant) arg.Expr).Value;\r
769                 }\r
770 \r
771                 static object GetFieldValue (Attribute a, string name)\r
772                 {\r
773                         int i;\r
774                         if (a.field_info_arr == null)\r
775                                 return null;\r
776                         i = 0;\r
777                         foreach (FieldInfo fi in a.field_info_arr) {\r
778                                 if (fi.Name == name)\r
779                                         return a.field_values_arr [i];\r
780                                 i++;\r
781                         }\r
782                         return null;\r
783                 }\r
784 \r
785                 static UnmanagedMarshal GetMarshal (Attribute a)\r
786                 {\r
787                         object o = GetFieldValue (a, "ArraySubType");\r
788                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;\r
789                         switch (a.UnmanagedType) {\r
790                         case UnmanagedType.CustomMarshaler:\r
791                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",\r
792                                                                        BindingFlags.Static | BindingFlags.Public);\r
793                                 if (define_custom == null)\r
794                                         return null;\r
795 \r
796                                 object [] args = new object [4];\r
797                                 args [0] = GetFieldValue (a, "MarshalTypeRef");\r
798                                 args [1] = GetFieldValue (a, "MarshalCookie");\r
799                                 args [2] = GetFieldValue (a, "MarshalType");\r
800                                 args [3] = Guid.Empty;\r
801                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);\r
802 \r
803                         case UnmanagedType.LPArray:                             \r
804                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);\r
805 \r
806                         case UnmanagedType.SafeArray:\r
807                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);\r
808 \r
809                         case UnmanagedType.ByValArray:\r
810                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));\r
811 \r
812                         case UnmanagedType.ByValTStr:\r
813                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));\r
814 \r
815                         default:\r
816                                 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
817                         }\r
818                 }\r
819 \r
820                 /// <summary>\r
821                 ///   Applies the attributes specified on target 'kind' to the `builder'.\r
822                 /// </summary>\r
823                 public static void ApplyAttributes (EmitContext ec, object builder, object kind,\r
824                                                     Attributes opt_attrs)\r
825                 {\r
826                         Type attr_type = null;\r
827                         \r
828                         if (opt_attrs == null)\r
829                                 return;\r
830                         if (opt_attrs.AttributeSections == null)\r
831                                 return;\r
832 \r
833                         ArrayList emitted_attrs = new ArrayList ();\r
834                         ArrayList emitted_targets = new ArrayList ();\r
835 \r
836                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
837                                 string attr_target = asec.Target;\r
838                                 \r
839                                 if (asec.Attributes == null)\r
840                                         continue;\r
841 \r
842                                 if (attr_target == "assembly" && !(builder is AssemblyBuilder))\r
843                                         continue;\r
844 \r
845                                 if (attr_target == "return" && !(builder is ParameterBuilder))\r
846                                         continue;\r
847                                 \r
848                                 foreach (Attribute a in asec.Attributes) {\r
849                                         Location loc = a.Location;\r
850                                         CustomAttributeBuilder cb = a.Resolve (ec);\r
851                                         attr_type = a.Type;\r
852 \r
853                                         if (cb == null) \r
854                                                 continue;\r
855                                         \r
856                                         if (!(kind is TypeContainer))\r
857                                                 if (!CheckAttributeTarget (a, kind)) {\r
858                                                         Error_AttributeNotValidForElement (a, loc);\r
859                                                         return;\r
860                                                 }\r
861 \r
862                                         //\r
863                                         // Perform the check for duplicate attributes\r
864                                         //\r
865                                         if (emitted_attrs.Contains (attr_type) &&\r
866                                             emitted_targets.Contains (attr_target) &&\r
867                                             !TypeManager.AreMultipleAllowed (attr_type)) {\r
868                                                 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");\r
869                                                 return;\r
870                                         }\r
871 \r
872                                         if (kind is Method || kind is Operator || kind is InterfaceMethod ||\r
873                                             kind is Accessor) {\r
874                                                 if (attr_type == TypeManager.methodimpl_attr_type) {\r
875                                                         if (a.ImplOptions == MethodImplOptions.InternalCall)\r
876                                                                 ((MethodBuilder) builder).\r
877                                                                 SetImplementationFlags (\r
878                                                                         MethodImplAttributes.InternalCall |\r
879                                                                         MethodImplAttributes.Runtime);\r
880                                                         else\r
881                                                                 ((MethodBuilder) builder).SetCustomAttribute (cb);\r
882                                                 } else if (attr_type != TypeManager.dllimport_type){\r
883                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);\r
884                                                 }\r
885                                         } else if (kind is Constructor) {\r
886                                                 ((ConstructorBuilder) builder).SetCustomAttribute (cb);\r
887                                         } else if (kind is Field) {\r
888                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
889                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
890                                                         if (marshal == null) {\r
891                                                                 Report.Warning (-24, loc,\r
892                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
893                                                                         "Please use the Mono runtime instead.");\r
894                                                         } else {\r
895                                                                 ((FieldBuilder) builder).SetMarshal (marshal);\r
896                                                         }\r
897                                                 } else { \r
898                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
899                                                 }\r
900                                         } else if (kind is Property || kind is Indexer ||\r
901                                                    kind is InterfaceProperty || kind is InterfaceIndexer) {\r
902                                                 ((PropertyBuilder) builder).SetCustomAttribute (cb);\r
903                                         } else if (kind is Event || kind is InterfaceEvent) {\r
904                                                 ((MyEventBuilder) builder).SetCustomAttribute (cb);\r
905                                         } else if (kind is ParameterBuilder) {\r
906 \r
907                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
908                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
909                                                         if (marshal == null) {\r
910                                                                 Report.Warning (-24, loc,\r
911                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
912                                                                         "Please use the Mono runtime instead.");\r
913                                                         } else {\r
914                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
915                                                         }\r
916                                                 } else { \r
917 \r
918                                                         try {\r
919                                                                 ((ParameterBuilder) builder).SetCustomAttribute (cb);\r
920                                                         } catch (System.ArgumentException) {\r
921                                                                 Report.Warning (-24, loc,\r
922                                                                                 "The Microsoft Runtime cannot set attributes \n" +\r
923                                                                                 "on the return type of a method. Please use the \n" +\r
924                                                                                 "Mono runtime instead.");\r
925                                                         }\r
926 \r
927                                                 }\r
928                                         } else if (kind is Enum) {\r
929                                                 ((TypeBuilder) builder).SetCustomAttribute (cb); \r
930 \r
931                                         } else if (kind is TypeContainer) {\r
932                                                 TypeContainer tc = (TypeContainer) kind;\r
933                                                 \r
934                                                 if (a.UsageAttr) {\r
935                                                         tc.Targets = a.Targets;\r
936                                                         tc.AllowMultiple = a.AllowMultiple;\r
937                                                         tc.Inherited = a.Inherited;\r
938 \r
939                                                         TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,\r
940                                                                                                     tc.AllowMultiple);\r
941                                                         \r
942                                                 } else if (attr_type == TypeManager.default_member_type) {\r
943                                                         if (tc.Indexers != null) {\r
944                                                                 Report.Error (646, loc,\r
945                                                                       "Cannot specify the DefaultMember attribute on" +\r
946                                                                       " a type containing an indexer");\r
947                                                                 return;\r
948                                                         }\r
949 \r
950                                                 } else {\r
951                                                         if (!CheckAttributeTarget (a, kind)) {\r
952                                                                 Error_AttributeNotValidForElement (a, loc);\r
953                                                                 return;\r
954                                                         }\r
955                                                 }\r
956 \r
957                                                 try {\r
958                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
959                                                 } catch (System.ArgumentException) {\r
960                                                         Report.Warning (\r
961                                                                 -21, loc,\r
962                                                 "The CharSet named property on StructLayout\n"+\r
963                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
964                                                 "\tYou might want to remove the CharSet declaration\n"+\r
965                                                 "\tor compile using the Mono runtime instead of the\n"+\r
966                                                 "\tMicrosoft .NET runtime");\r
967                                                 }\r
968                                         } else if (kind is Delegate){\r
969                                                 if (!CheckAttributeTarget (a, kind)) {\r
970                                                         Error_AttributeNotValidForElement (a, loc);\r
971                                                         return;\r
972                                                 }\r
973                                                 try {\r
974                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
975                                                 } catch (System.ArgumentException) {\r
976                                                         Report.Warning (\r
977                                                                 -21, loc,\r
978                                                 "The CharSet named property on StructLayout\n"+\r
979                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
980                                                 "\tYou might want to remove the CharSet declaration\n"+\r
981                                                 "\tor compile using the Mono runtime instead of the\n"+\r
982                                                 "\tMicrosoft .NET runtime");\r
983                                                 }\r
984                                         } else if (kind is Interface) {\r
985                                                 Interface iface = (Interface) kind;\r
986 \r
987                                                 if ((attr_type == TypeManager.default_member_type) &&\r
988                                                     (iface.InterfaceIndexers != null)) {\r
989                                                         Report.Error (\r
990                                                                 646, loc,\r
991                                                                 "Cannot specify the DefaultMember attribute on" +\r
992                                                                 " a type containing an indexer");\r
993                                                         return;\r
994                                                 }\r
995 \r
996                                                 if (!CheckAttributeTarget (a, kind)) {\r
997                                                         Error_AttributeNotValidForElement (a, loc);\r
998                                                         return;\r
999                                                 }\r
1000 \r
1001                                                 ((TypeBuilder) builder).SetCustomAttribute (cb);\r
1002                                         } else if (kind is AssemblyBuilder){\r
1003                                                 ((AssemblyBuilder) builder).SetCustomAttribute (cb);\r
1004                                         } else if (kind is ModuleBuilder) {\r
1005                                                 ((ModuleBuilder) builder).SetCustomAttribute (cb);\r
1006                                         } else if (kind is FieldBuilder) {\r
1007                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
1008                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
1009                                                         if (marshal == null) {\r
1010                                                                 Report.Warning (-24, loc,\r
1011                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
1012                                                                         "Please use the Mono runtime instead.");\r
1013                                                         } else {\r
1014                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
1015                                                         }\r
1016                                                 } else { \r
1017                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
1018                                                 }\r
1019                                         } else\r
1020                                                 throw new Exception ("Unknown kind: " + kind);\r
1021 \r
1022                                         //\r
1023                                         // Once an attribute type has been emitted once we\r
1024                                         // keep track of the info to prevent multiple occurences\r
1025                                         // for attributes which do not explicitly allow it\r
1026                                         //\r
1027                                         if (!emitted_attrs.Contains (attr_type))\r
1028                                                 emitted_attrs.Add (attr_type);\r
1029 \r
1030                                         //\r
1031                                         // We keep of this target-wise and so emitted targets\r
1032                                         // are tracked too\r
1033                                         //\r
1034                                         if (!emitted_targets.Contains (attr_target))\r
1035                                                 emitted_targets.Add (attr_target);\r
1036                                 }\r
1037                                 \r
1038                                 \r
1039                         }\r
1040                 }\r
1041 \r
1042                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,\r
1043                                                           MethodAttributes flags, Type ret_type, Type [] param_types)\r
1044                 {\r
1045                         //\r
1046                         // We extract from the attribute the information we need \r
1047                         //\r
1048 \r
1049                         if (Arguments == null) {\r
1050                                 Console.WriteLine ("Internal error : this is not supposed to happen !");\r
1051                                 return null;\r
1052                         }\r
1053 \r
1054                         Type = CheckAttributeType (ec);\r
1055                         if (Type == null)\r
1056                                 return null;\r
1057                         \r
1058                         ArrayList named_args = new ArrayList ();\r
1059                         \r
1060                         ArrayList pos_args = (ArrayList) Arguments [0];\r
1061                         if (Arguments.Count > 1)\r
1062                                 named_args = (ArrayList) Arguments [1];\r
1063                         \r
1064 \r
1065                         string dll_name = null;\r
1066                         \r
1067                         Argument tmp = (Argument) pos_args [0];\r
1068 \r
1069                         if (!tmp.Resolve (ec, Location))\r
1070                                 return null;\r
1071                         \r
1072                         if (tmp.Expr is Constant)\r
1073                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();\r
1074                         else { \r
1075                                 Error_AttributeArgumentNotValid (Location);\r
1076                                 return null;\r
1077                         }\r
1078 \r
1079                         // Now we process the named arguments\r
1080                         CallingConvention cc = CallingConvention.Winapi;\r
1081                         CharSet charset = CharSet.Ansi;\r
1082                         bool preserve_sig = true;\r
1083 #if FIXME\r
1084                         bool exact_spelling = false;\r
1085 #endif\r
1086                         bool set_last_err = false;\r
1087                         string entry_point = null;\r
1088 \r
1089                         for (int i = 0; i < named_args.Count; i++) {\r
1090 \r
1091                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
1092 \r
1093                                 string member_name = (string) de.Key;\r
1094                                 Argument a  = (Argument) de.Value;\r
1095 \r
1096                                 if (!a.Resolve (ec, Location))\r
1097                                         return null;\r
1098 \r
1099                                 Expression member = Expression.MemberLookup (\r
1100                                         ec, Type, member_name, \r
1101                                         MemberTypes.Field | MemberTypes.Property,\r
1102                                         BindingFlags.Public | BindingFlags.Instance,\r
1103                                         Location);\r
1104 \r
1105                                 if (member == null || !(member is FieldExpr)) {\r
1106                                         Error_InvalidNamedArgument (member_name);\r
1107                                         return null;\r
1108                                 }\r
1109 \r
1110                                 if (member is FieldExpr) {\r
1111                                         FieldExpr fe = (FieldExpr) member;\r
1112                                         FieldInfo fi = fe.FieldInfo;\r
1113 \r
1114                                         if (fi.IsInitOnly) {\r
1115                                                 Error_InvalidNamedArgument (member_name);\r
1116                                                 return null;\r
1117                                         }\r
1118 \r
1119                                         if (a.Expr is Constant) {\r
1120                                                 Constant c = (Constant) a.Expr;\r
1121                                                 \r
1122                                                 if (member_name == "CallingConvention")\r
1123                                                         cc = (CallingConvention) c.GetValue ();\r
1124                                                 else if (member_name == "CharSet")\r
1125                                                         charset = (CharSet) c.GetValue ();\r
1126                                                 else if (member_name == "EntryPoint")\r
1127                                                         entry_point = (string) c.GetValue ();\r
1128                                                 else if (member_name == "SetLastError")\r
1129                                                         set_last_err = (bool) c.GetValue ();\r
1130 #if FIXME\r
1131                                                 else if (member_name == "ExactSpelling")\r
1132                                                         exact_spelling = (bool) c.GetValue ();\r
1133 #endif\r
1134                                                 else if (member_name == "PreserveSig")\r
1135                                                         preserve_sig = (bool) c.GetValue ();\r
1136                                         } else { \r
1137                                                 Error_AttributeArgumentNotValid (Location);\r
1138                                                 return null;\r
1139                                         }\r
1140                                         \r
1141                                 }\r
1142                         }\r
1143 \r
1144                         if (entry_point == null)\r
1145                                 entry_point = name;\r
1146                         if (set_last_err)\r
1147                                 charset = (CharSet)((int)charset | 0x40);\r
1148                         \r
1149                         MethodBuilder mb = builder.DefinePInvokeMethod (\r
1150                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,\r
1151                                 CallingConventions.Standard,\r
1152                                 ret_type,\r
1153                                 param_types,\r
1154                                 cc,\r
1155                                 charset);\r
1156 \r
1157                         if (preserve_sig)\r
1158                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);\r
1159                         \r
1160                         return mb;\r
1161                 }\r
1162                 \r
1163         }\r
1164         \r
1165         public class AttributeSection {\r
1166                 public readonly string    Target;\r
1167                 public readonly ArrayList Attributes;\r
1168                 \r
1169                 public AttributeSection (string target, ArrayList attrs)\r
1170                 {\r
1171                         Target = target;\r
1172                         Attributes = attrs;\r
1173                 }\r
1174                 \r
1175         }\r
1176 \r
1177         public class Attributes {\r
1178                 public ArrayList AttributeSections;\r
1179 \r
1180                 public Attributes (AttributeSection a)\r
1181                 {\r
1182                         AttributeSections = new ArrayList ();\r
1183                         AttributeSections.Add (a);\r
1184 \r
1185                 }\r
1186 \r
1187                 public void AddAttributeSection (AttributeSection a)\r
1188                 {\r
1189                         if (a != null && !AttributeSections.Contains (a))\r
1190                                 AttributeSections.Add (a);\r
1191                 }\r
1192 \r
1193                 public bool Contains (Type t)\r
1194                 {\r
1195                         foreach (AttributeSection attr_section in AttributeSections){\r
1196                                 foreach (Attribute a in attr_section.Attributes){\r
1197                                         if (a.Type == t)\r
1198                                                 return true;\r
1199                                 }\r
1200                         }\r
1201                         \r
1202                         return false;\r
1203                 }\r
1204         }\r
1205 }\r