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