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