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