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