Use Mono_IsInflatedMethod.
[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, false, 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) {\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 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 Accessor) {
635                                 if ((targets & AttributeTargets.Property) != 0)\r
636                                         return true;\r
637                                 else\r
638                                         return false;\r
639                         } else if (element is AssemblyClass){
640                                 if ((targets & AttributeTargets.Assembly) != 0)\r
641                                         return true;\r
642                                 else\r
643                                         return false;\r
644                         } else if (element is ModuleClass){
645                                 if ((targets & AttributeTargets.Module) != 0)
646                                         return true;
647                                 else
648                                         return false;
649                         }\r
650 \r
651                         return false;\r
652                 }\r
653 \r
654                 //\r
655                 // This method should be invoked to pull the IndexerName attribute from an\r
656                 // Indexer if it exists.\r
657                 //\r
658                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)\r
659                 {\r
660                         if (opt_attrs == null)\r
661                                 return null;\r
662                         if (opt_attrs.AttributeSections == null)\r
663                                 return null;\r
664 \r
665                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
666                                 if (asec.Attributes == null)\r
667                                         continue;\r
668 \r
669                                 foreach (Attribute a in asec.Attributes){\r
670                                         if (a.ResolveType (ec) == null)\r
671                                                 return null;\r
672 \r
673                                         if (a.Type != TypeManager.indexer_name_type)\r
674                                                 continue;\r
675 \r
676                                         //\r
677                                         // So we have found an IndexerName, pull the data out.\r
678                                         //\r
679                                         if (a.Arguments == null || a.Arguments [0] == null){\r
680                                                 Error_AttributeConstructorMismatch (a.Location);\r
681                                                 return null;\r
682                                         }\r
683                                         ArrayList pos_args = (ArrayList) a.Arguments [0];\r
684                                         if (pos_args.Count == 0){\r
685                                                 Error_AttributeConstructorMismatch (a.Location);\r
686                                                 return null;\r
687                                         }\r
688                                         \r
689                                         Argument arg = (Argument) pos_args [0];\r
690                                         if (!arg.Resolve (ec, a.Location))\r
691                                                 return null;\r
692                                         \r
693                                         Expression e = arg.Expr;\r
694                                         if (!(e is StringConstant)){\r
695                                                 Error_AttributeConstructorMismatch (a.Location);\r
696                                                 return null;\r
697                                         }\r
698 \r
699                                         //\r
700                                         // Remove the attribute from the list\r
701                                         //\r
702                                         asec.Attributes.Remove (a);\r
703 \r
704                                         return (((StringConstant) e).Value);\r
705                                 }\r
706                         }\r
707                         return null;\r
708                 }\r
709 \r
710                 //\r
711                 // This pulls the condition name out of a Conditional attribute\r
712                 //\r
713                 public string Conditional_GetConditionName ()\r
714                 {\r
715                         //\r
716                         // So we have a Conditional, pull the data out.\r
717                         //\r
718                         if (Arguments == null || Arguments [0] == null){\r
719                                 Error_AttributeConstructorMismatch (Location);\r
720                                 return null;\r
721                         }\r
722 \r
723                         ArrayList pos_args = (ArrayList) Arguments [0];\r
724                         if (pos_args.Count != 1){\r
725                                 Error_AttributeConstructorMismatch (Location);\r
726                                 return null;\r
727                         }\r
728 \r
729                         Argument arg = (Argument) pos_args [0]; \r
730                         if (!(arg.Expr is StringConstant)){\r
731                                 Error_AttributeConstructorMismatch (Location);\r
732                                 return null;\r
733                         }\r
734 \r
735                         return ((StringConstant) arg.Expr).Value;\r
736                 }\r
737 \r
738                 //\r
739                 // This pulls the obsolete message and error flag out of an Obsolete attribute\r
740                 //\r
741                 public string Obsolete_GetObsoleteMessage (out bool is_error)\r
742                 {\r
743                         is_error = false;\r
744                         //\r
745                         // So we have an Obsolete, pull the data out.\r
746                         //\r
747                         if (Arguments == null || Arguments [0] == null)\r
748                                 return "";\r
749 \r
750                         ArrayList pos_args = (ArrayList) Arguments [0];\r
751                         if (pos_args.Count == 0)\r
752                                 return "";\r
753                         else if (pos_args.Count > 2){\r
754                                 Error_AttributeConstructorMismatch (Location);\r
755                                 return null;\r
756                         }\r
757 \r
758                         Argument arg = (Argument) pos_args [0]; \r
759                         if (!(arg.Expr is StringConstant)){\r
760                                 Error_AttributeConstructorMismatch (Location);\r
761                                 return null;\r
762                         }\r
763 \r
764                         if (pos_args.Count == 2){\r
765                                 Argument arg2 = (Argument) pos_args [1];\r
766                                 if (!(arg2.Expr is BoolConstant)){\r
767                                         Error_AttributeConstructorMismatch (Location);\r
768                                         return null;\r
769                                 }\r
770                                 is_error = ((BoolConstant) arg2.Expr).Value;\r
771                         }\r
772 \r
773                         return ((StringConstant) arg.Expr).Value;\r
774                 }\r
775 \r
776                 static object GetFieldValue (Attribute a, string name)\r
777                 {\r
778                         int i;\r
779                         if (a.field_info_arr == null)\r
780                                 return null;\r
781                         i = 0;\r
782                         foreach (FieldInfo fi in a.field_info_arr) {\r
783                                 if (fi.Name == name)\r
784                                         return a.field_values_arr [i];\r
785                                 i++;\r
786                         }\r
787                         return null;\r
788                 }\r
789 \r
790                 static UnmanagedMarshal GetMarshal (Attribute a)\r
791                 {\r
792                         object o = GetFieldValue (a, "ArraySubType");\r
793                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;\r
794                         switch (a.UnmanagedType) {\r
795                         case UnmanagedType.CustomMarshaler:\r
796                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",\r
797                                                                        BindingFlags.Static | BindingFlags.Public);\r
798                                 if (define_custom == null)\r
799                                         return null;\r
800 \r
801                                 object [] args = new object [4];\r
802                                 args [0] = GetFieldValue (a, "MarshalTypeRef");\r
803                                 args [1] = GetFieldValue (a, "MarshalCookie");\r
804                                 args [2] = GetFieldValue (a, "MarshalType");\r
805                                 args [3] = Guid.Empty;\r
806                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);\r
807 \r
808                         case UnmanagedType.LPArray:                             \r
809                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);\r
810 \r
811                         case UnmanagedType.SafeArray:\r
812                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);\r
813 \r
814                         case UnmanagedType.ByValArray:\r
815                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));\r
816 \r
817                         case UnmanagedType.ByValTStr:\r
818                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));\r
819 \r
820                         default:\r
821                                 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
822                         }\r
823                 }\r
824 \r
825                 /// <summary>\r
826                 ///   Applies the attributes specified on target 'kind' to the `builder'.\r
827                 /// </summary>\r
828                 public static void ApplyAttributes (EmitContext ec, object builder, object kind,\r
829                                                     Attributes opt_attrs)\r
830                 {\r
831                         Type attr_type = null;\r
832                         \r
833                         if (opt_attrs == null)\r
834                                 return;\r
835                         if (opt_attrs.AttributeSections == null)\r
836                                 return;\r
837 \r
838                         ArrayList emitted_attrs = new ArrayList ();\r
839                         ArrayList emitted_targets = new ArrayList ();\r
840 \r
841                         foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
842                                 string attr_target = asec.Target;\r
843                                 \r
844                                 if (asec.Attributes == null)\r
845                                         continue;\r
846 \r
847                                 if (attr_target == "return" && !(builder is ParameterBuilder))\r
848                                         continue;\r
849                                 \r
850                                 foreach (Attribute a in asec.Attributes) {\r
851                                         Location loc = a.Location;\r
852                                         CustomAttributeBuilder cb = a.Resolve (ec);\r
853                                         attr_type = a.Type;\r
854 \r
855                                         if (cb == null) \r
856                                                 continue;\r
857                                         \r
858                                         if (!(kind is TypeContainer))\r
859                                                 if (!CheckAttributeTarget (a, kind)) {\r
860                                                         Error_AttributeNotValidForElement (a, loc);\r
861                                                         return;\r
862                                                 }\r
863 \r
864                                         //\r
865                                         // Perform the check for duplicate attributes\r
866                                         //\r
867                                         if (emitted_attrs.Contains (attr_type) &&\r
868                                             emitted_targets.Contains (attr_target) &&\r
869                                             !TypeManager.AreMultipleAllowed (attr_type)) {\r
870                                                 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");\r
871                                                 return;\r
872                                         }\r
873 \r
874                                         if (kind is IAttributeSupport) {
875                                                 if (attr_type == TypeManager.methodimpl_attr_type && a.ImplOptions == MethodImplOptions.InternalCall) {
876                                                         ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
877                                                 } 
878                                                 else {
879                                                         IAttributeSupport attributeSupport = kind as IAttributeSupport;
880                                                         attributeSupport.SetCustomAttribute (cb);
881                                                 }
882                                         }
883                                         else if (kind is Method || kind is Operator || kind is Accessor) {\r
884                                                 if (attr_type == TypeManager.methodimpl_attr_type) {\r
885                                                         if (a.ImplOptions == MethodImplOptions.InternalCall)\r
886                                                                 ((MethodBuilder) builder).\r
887                                                                 SetImplementationFlags (\r
888                                                                         MethodImplAttributes.InternalCall |\r
889                                                                         MethodImplAttributes.Runtime);\r
890                                                         else\r
891                                                                 ((MethodBuilder) builder).SetCustomAttribute (cb);\r
892                                                 } else if (attr_type != TypeManager.dllimport_type){\r
893                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);\r
894                                                 }\r
895                                         } else if (kind is Constructor) {\r
896                                                 ((ConstructorBuilder) builder).SetCustomAttribute (cb);\r
897                                         } else if (kind is Field) {\r
898                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
899                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
900                                                         if (marshal == null) {\r
901                                                                 Report.Warning (-24, loc,\r
902                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
903                                                                         "Please use the Mono runtime instead.");\r
904                                                         } else {\r
905                                                                 ((FieldBuilder) builder).SetMarshal (marshal);\r
906                                                         }\r
907                                                 } else { \r
908                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
909                                                 }\r
910                                         } else if (kind is Property || kind is Indexer) {\r
911
912                                                 if (builder is PropertyBuilder) 
913                                                 ((PropertyBuilder) builder).SetCustomAttribute (cb);\r
914                                                 //
915                                                 // This is for the case we are setting attributes on
916                                                 // the get and set accessors
917                                                 //
918                                                 else if (builder is MethodBuilder)
919                                                         ((MethodBuilder) builder).SetCustomAttribute (cb);
920                                         } else if (kind is Event) {\r
921                                                 ((MyEventBuilder) builder).SetCustomAttribute (cb);\r
922                                         } else if (kind is ParameterBuilder) {\r
923 \r
924                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
925                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
926                                                         if (marshal == null) {\r
927                                                                 Report.Warning (-24, loc,\r
928                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
929                                                                         "Please use the Mono runtime instead.");\r
930                                                         } else {\r
931                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
932                                                         }\r
933                                                 } else { \r
934 \r
935                                                         try {\r
936                                                                 ((ParameterBuilder) builder).SetCustomAttribute (cb);\r
937                                                         } catch (System.ArgumentException) {\r
938                                                                 Report.Warning (-24, loc,\r
939                                                                                 "The Microsoft Runtime cannot set attributes \n" +\r
940                                                                                 "on the return type of a method. Please use the \n" +\r
941                                                                                 "Mono runtime instead.");\r
942                                                         }\r
943 \r
944                                                 }\r
945                                         } else if (kind is Enum) {\r
946                                                 ((TypeBuilder) builder).SetCustomAttribute (cb); \r
947 \r
948                                         } else if (kind is TypeContainer) {\r
949                                                 TypeContainer tc = (TypeContainer) kind;\r
950                                                 \r
951                                                 if (a.UsageAttr) {\r
952                                                         tc.Targets = a.Targets;\r
953                                                         tc.AllowMultiple = a.AllowMultiple;\r
954                                                         tc.Inherited = a.Inherited;\r
955 \r
956                                                         TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,\r
957                                                                                                     tc.AllowMultiple);\r
958                                                         \r
959                                                 } else if (attr_type == TypeManager.default_member_type) {\r
960                                                         if (tc.Indexers != null) {\r
961                                                                 Report.Error (646, loc,\r
962                                                                       "Cannot specify the DefaultMember attribute on" +\r
963                                                                       " a type containing an indexer");\r
964                                                                 return;\r
965                                                         }\r
966 \r
967                                                 } else {\r
968                                                         if (!CheckAttributeTarget (a, kind)) {\r
969                                                                 Error_AttributeNotValidForElement (a, loc);\r
970                                                                 return;\r
971                                                         }\r
972                                                 }\r
973 \r
974                                                 try {\r
975                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
976                                                 } catch (System.ArgumentException) {\r
977                                                         Report.Warning (\r
978                                                                 -21, loc,\r
979                                                 "The CharSet named property on StructLayout\n"+\r
980                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
981                                                 "\tYou might want to remove the CharSet declaration\n"+\r
982                                                 "\tor compile using the Mono runtime instead of the\n"+\r
983                                                 "\tMicrosoft .NET runtime");\r
984                                                 }\r
985                                         } else if (kind is Delegate){\r
986                                                 if (!CheckAttributeTarget (a, kind)) {\r
987                                                         Error_AttributeNotValidForElement (a, loc);\r
988                                                         return;\r
989                                                 }\r
990                                                 try {\r
991                                                         ((TypeBuilder) builder).SetCustomAttribute (cb);\r
992                                                 } catch (System.ArgumentException) {\r
993                                                         Report.Warning (\r
994                                                                 -21, loc,\r
995                                                 "The CharSet named property on StructLayout\n"+\r
996                                                 "\tdoes not work correctly on Microsoft.NET\n"+\r
997                                                 "\tYou might want to remove the CharSet declaration\n"+\r
998                                                 "\tor compile using the Mono runtime instead of the\n"+\r
999                                                 "\tMicrosoft .NET runtime");\r
1000                                                 }\r
1001                                         } else if (kind is Interface) {\r
1002                                                 Interface iface = (Interface) kind;\r
1003 \r
1004                                                 if ((attr_type == TypeManager.default_member_type) &&\r
1005                                                     (iface.Indexers != null)) {\r
1006                                                         Report.Error (\r
1007                                                                 646, loc,\r
1008                                                                 "Cannot specify the DefaultMember attribute on" +\r
1009                                                                 " a type containing an indexer");\r
1010                                                         return;\r
1011                                                 }\r
1012 \r
1013                                                 if (!CheckAttributeTarget (a, kind)) {\r
1014                                                         Error_AttributeNotValidForElement (a, loc);\r
1015                                                         return;\r
1016                                                 }\r
1017 \r
1018                                                 ((TypeBuilder) builder).SetCustomAttribute (cb);\r
1019                                         } else if (kind is AssemblyBuilder){\r
1020                                                 ((AssemblyBuilder) builder).SetCustomAttribute (cb);\r
1021                                         } else if (kind is ModuleBuilder) {\r
1022                                                 ((ModuleBuilder) builder).SetCustomAttribute (cb);\r
1023                                         } else if (kind is FieldBuilder) {\r
1024                                                 if (attr_type == TypeManager.marshal_as_attr_type) {\r
1025                                                         UnmanagedMarshal marshal = GetMarshal (a);\r
1026                                                         if (marshal == null) {\r
1027                                                                 Report.Warning (-24, loc,\r
1028                                                                         "The Microsoft Runtime cannot set this marshal info. " +\r
1029                                                                         "Please use the Mono runtime instead.");\r
1030                                                         } else {\r
1031                                                                 ((ParameterBuilder) builder).SetMarshal (marshal);\r
1032                                                         }\r
1033                                                 } else { \r
1034                                                         ((FieldBuilder) builder).SetCustomAttribute (cb);\r
1035                                                 }\r
1036                                         } else\r
1037                                                 throw new Exception ("Unknown kind: " + kind);\r
1038 \r
1039                                         //\r
1040                                         // Once an attribute type has been emitted once we\r
1041                                         // keep track of the info to prevent multiple occurences\r
1042                                         // for attributes which do not explicitly allow it\r
1043                                         //\r
1044                                         if (!emitted_attrs.Contains (attr_type))\r
1045                                                 emitted_attrs.Add (attr_type);\r
1046 \r
1047                                         //\r
1048                                         // We keep of this target-wise and so emitted targets\r
1049                                         // are tracked too\r
1050                                         //\r
1051                                         if (!emitted_targets.Contains (attr_target))\r
1052                                                 emitted_targets.Add (attr_target);\r
1053                                 }\r
1054                                 \r
1055                                 \r
1056                         }\r
1057                 }\r
1058 \r
1059                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,\r
1060                                                           MethodAttributes flags, Type ret_type, Type [] param_types)\r
1061                 {\r
1062                         //\r
1063                         // We extract from the attribute the information we need \r
1064                         //\r
1065 \r
1066                         if (Arguments == null) {\r
1067                                 Console.WriteLine ("Internal error : this is not supposed to happen !");\r
1068                                 return null;\r
1069                         }\r
1070 \r
1071                         Type = CheckAttributeType (ec);\r
1072                         if (Type == null)\r
1073                                 return null;\r
1074                         \r
1075                         ArrayList named_args = new ArrayList ();\r
1076                         \r
1077                         ArrayList pos_args = (ArrayList) Arguments [0];\r
1078                         if (Arguments.Count > 1)\r
1079                                 named_args = (ArrayList) Arguments [1];\r
1080                         \r
1081 \r
1082                         string dll_name = null;\r
1083                         \r
1084                         Argument tmp = (Argument) pos_args [0];\r
1085 \r
1086                         if (!tmp.Resolve (ec, Location))\r
1087                                 return null;\r
1088                         \r
1089                         if (tmp.Expr is Constant)\r
1090                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();\r
1091                         else { \r
1092                                 Error_AttributeArgumentNotValid (Location);\r
1093                                 return null;\r
1094                         }\r
1095 \r
1096                         // Now we process the named arguments\r
1097                         CallingConvention cc = CallingConvention.Winapi;\r
1098                         CharSet charset = CharSet.Ansi;\r
1099                         bool preserve_sig = true;\r
1100 #if FIXME\r
1101                         bool exact_spelling = false;\r
1102 #endif\r
1103                         bool set_last_err = false;\r
1104                         string entry_point = null;\r
1105 \r
1106                         for (int i = 0; i < named_args.Count; i++) {\r
1107 \r
1108                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
1109 \r
1110                                 string member_name = (string) de.Key;\r
1111                                 Argument a  = (Argument) de.Value;\r
1112 \r
1113                                 if (!a.Resolve (ec, Location))\r
1114                                         return null;\r
1115 \r
1116                                 Expression member = Expression.MemberLookup (\r
1117                                         ec, Type, member_name, \r
1118                                         MemberTypes.Field | MemberTypes.Property,\r
1119                                         BindingFlags.Public | BindingFlags.Instance,\r
1120                                         Location);\r
1121 \r
1122                                 if (member == null || !(member is FieldExpr)) {\r
1123                                         Error_InvalidNamedArgument (member_name);\r
1124                                         return null;\r
1125                                 }\r
1126 \r
1127                                 if (member is FieldExpr) {\r
1128                                         FieldExpr fe = (FieldExpr) member;\r
1129                                         FieldInfo fi = fe.FieldInfo;\r
1130 \r
1131                                         if (fi.IsInitOnly) {\r
1132                                                 Error_InvalidNamedArgument (member_name);\r
1133                                                 return null;\r
1134                                         }\r
1135 \r
1136                                         if (a.Expr is Constant) {\r
1137                                                 Constant c = (Constant) a.Expr;\r
1138                                                 \r
1139                                                 if (member_name == "CallingConvention")\r
1140                                                         cc = (CallingConvention) c.GetValue ();\r
1141                                                 else if (member_name == "CharSet")\r
1142                                                         charset = (CharSet) c.GetValue ();\r
1143                                                 else if (member_name == "EntryPoint")\r
1144                                                         entry_point = (string) c.GetValue ();\r
1145                                                 else if (member_name == "SetLastError")\r
1146                                                         set_last_err = (bool) c.GetValue ();\r
1147 #if FIXME\r
1148                                                 else if (member_name == "ExactSpelling")\r
1149                                                         exact_spelling = (bool) c.GetValue ();\r
1150 #endif\r
1151                                                 else if (member_name == "PreserveSig")\r
1152                                                         preserve_sig = (bool) c.GetValue ();\r
1153                                         } else { \r
1154                                                 Error_AttributeArgumentNotValid (Location);\r
1155                                                 return null;\r
1156                                         }\r
1157                                         \r
1158                                 }\r
1159                         }\r
1160 \r
1161                         if (entry_point == null)\r
1162                                 entry_point = name;\r
1163                         if (set_last_err)\r
1164                                 charset = (CharSet)((int)charset | 0x40);\r
1165                         \r
1166                         MethodBuilder mb = builder.DefinePInvokeMethod (\r
1167                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,\r
1168                                 CallingConventions.Standard,\r
1169                                 ret_type,\r
1170                                 param_types,\r
1171                                 cc,\r
1172                                 charset);\r
1173 \r
1174                         if (preserve_sig)\r
1175                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);\r
1176                         \r
1177                         return mb;\r
1178                 }\r
1179                 \r
1180         }\r
1181         \r
1182         public class AttributeSection {\r
1183                 public readonly string    Target;\r
1184                 public readonly ArrayList Attributes;\r
1185                 \r
1186                 public AttributeSection (string target, ArrayList attrs)\r
1187                 {\r
1188                         Target = target;\r
1189                         Attributes = attrs;\r
1190                 }\r
1191                 \r
1192         }\r
1193 \r
1194         public class Attributes {\r
1195                 public ArrayList AttributeSections;\r
1196 \r
1197                 public Attributes (AttributeSection a)\r
1198                 {\r
1199                         AttributeSections = new ArrayList ();\r
1200                         AttributeSections.Add (a);\r
1201 \r
1202                 }\r
1203 \r
1204                 public void AddAttributeSection (AttributeSection a)\r
1205                 {\r
1206                         if (a != null && !AttributeSections.Contains (a))\r
1207                                 AttributeSections.Add (a);\r
1208                 }\r
1209 \r
1210                 public bool Contains (Type t)\r
1211                 {\r
1212                         foreach (AttributeSection attr_section in AttributeSections){\r
1213                                 foreach (Attribute a in attr_section.Attributes){\r
1214                                         if (a.Type == t)\r
1215                                                 return true;\r
1216                                 }\r
1217                         }\r
1218                         \r
1219                         return false;\r
1220                 }\r
1221         }\r
1222
1223         public interface IAttributeSupport {
1224                 void SetCustomAttribute (CustomAttributeBuilder customBuilder);
1225         }
1226 }\r