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