**** Merged from MCS ****
[mono.git] / mcs / gmcs / attribute.cs
1 // -*- coding: dos -*-\r
2 //\r
3 // attribute.cs: Attribute Handler\r
4 //\r
5 // Author: Ravi Pratap (ravi@ximian.com)\r
6 //\r
7 // Licensed under the terms of the GNU GPL\r
8 //\r
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)\r
10 //\r
11 //\r
12 \r
13 using System;\r
14 using System.Diagnostics;\r
15 using System.Collections;\r
16 using System.Collections.Specialized;\r
17 using System.Reflection;\r
18 using System.Reflection.Emit;\r
19 using System.Runtime.InteropServices;\r
20 using System.Runtime.CompilerServices;\r
21 using System.Text;\r
22 \r
23 namespace Mono.CSharp {\r
24         /// <summary>\r
25         ///   Base class for objects that can have Attributes applied to them.\r
26         /// </summary>\r
27         public abstract class Attributable {\r
28                 /// <summary>\r
29                 ///   Attributes for this type\r
30                 /// </summary>\r
31                 Attributes attributes;\r
32 \r
33                 public Attributable(Attributes attrs)\r
34                 {\r
35                         attributes = attrs;\r
36                         if (attributes != null)\r
37                                 attributes.CheckTargets (ValidAttributeTargets);\r
38                 }\r
39 \r
40                 public Attributes OptAttributes \r
41                 {\r
42                         get {\r
43                                 return attributes;\r
44                         }\r
45                         set {\r
46                                 attributes = value;\r
47                         }\r
48                 }\r
49 \r
50                 /// <summary>\r
51                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder\r
52                 /// </summary>\r
53                 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);\r
54 \r
55                 /// <summary>\r
56                 /// Returns combination of enabled AttributeTargets\r
57                 /// </summary>\r
58                 public abstract AttributeTargets AttributeTargets { get; }\r
59 \r
60                 public abstract bool IsClsCompliaceRequired (DeclSpace ds);\r
61 \r
62                 /// <summary>\r
63                 /// Gets list of valid attribute targets for explicit target declaration\r
64                 /// </summary>\r
65                 protected abstract string[] ValidAttributeTargets { get; }\r
66         };\r
67 \r
68         public class Attribute {\r
69                 public readonly string Target;\r
70                 public readonly string    Name;\r
71                 public readonly ArrayList Arguments;\r
72 \r
73                 public readonly Location Location;\r
74 \r
75                 public Type Type;\r
76                 \r
77                 // Is non-null if type is AttributeUsageAttribute\r
78                 AttributeUsageAttribute usage_attribute;\r
79 \r
80                 public AttributeUsageAttribute UsageAttribute {\r
81                         get {\r
82                                 return usage_attribute;\r
83                         }\r
84                 }\r
85 \r
86                 MethodImplOptions ImplOptions;\r
87                 UnmanagedType     UnmanagedType;\r
88                 CustomAttributeBuilder cb;\r
89         \r
90                 // non-null if named args present after Resolve () is called\r
91                 PropertyInfo [] prop_info_arr;\r
92                 FieldInfo [] field_info_arr;\r
93                 object [] field_values_arr;\r
94                 object [] prop_values_arr;\r
95                 \r
96                 object [] pos_values;\r
97 \r
98                 static PtrHashtable usage_attr_cache = new PtrHashtable ();\r
99 \r
100                 public Attribute (string target, string name, ArrayList args, Location loc)\r
101                 {\r
102                         Name = name;\r
103                         Arguments = args;\r
104                         Location = loc;\r
105                         Target = target;\r
106                 }\r
107 \r
108                 void Error_InvalidNamedArgument (string name)\r
109                 {\r
110                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +\r
111                                       "argument. Named attribute arguments must be fields which are not " +\r
112                                       "readonly, static or const, or properties with a set accessor which "+\r
113                                       "are not static.");\r
114                 }\r
115 \r
116                 static void Error_AttributeArgumentNotValid (Location loc)\r
117                 {\r
118                         Report.Error (182, loc,\r
119                                       "An attribute argument must be a constant expression, typeof " +\r
120                                       "expression or array creation expression");\r
121                 }\r
122 \r
123                 static void Error_AttributeConstructorMismatch (Location loc)\r
124                 {\r
125                         Report.Error (-6, loc,\r
126                                       "Could not find a constructor for this argument list.");\r
127                 }\r
128 \r
129                 static void Error_TypeParameterInAttribute (Location loc)\r
130                 {\r
131                         Report.Error (\r
132                                 -202, loc, "Can not use a type parameter in an attribute");\r
133                 }\r
134 \r
135                 /// <summary>\r
136                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.\r
137                 /// </summary>\r
138                 protected virtual Type CheckAttributeType (EmitContext ec, bool complain)\r
139                 {\r
140                         TypeExpr t1 = RootContext.LookupType (ec.DeclSpace, Name, true, Location);\r
141                         // FIXME: Shouldn't do this for quoted attributes: [@A]\r
142                         TypeExpr t2 = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);\r
143 \r
144                         String err0616 = null;\r
145                         if (t1 != null && ! t1.IsAttribute) {\r
146                                 t1 = null;\r
147                                 err0616 = "'" + Name + "': is not an attribute class";\r
148                         }\r
149                         if (t2 != null && ! t2.IsAttribute) {\r
150                                 t2 = null;\r
151                                 err0616 = (err0616 != null) \r
152                                         ? "Neither '" + Name + "' nor '" + Name + "Attribute' is an attribute class"\r
153                                         : "'" + Name + "Attribute': is not an attribute class";\r
154                         }\r
155 \r
156                         if (t1 != null && t2 != null) {\r
157                                 Report.Error(1614, Location, "'" + Name + "': is ambiguous; " \r
158                                              + " use either '@" + Name + "' or '" + Name + "Attribute'");\r
159                                 return null;\r
160                         }\r
161 \r
162                         if (t1 != null)\r
163                                 return t1.ResolveType (ec);\r
164                         if (t2 != null)\r
165                                 return t2.ResolveType (ec);\r
166                         if (err0616 != null) {\r
167                                 Report.Error (616, Location, err0616);\r
168                                 return null;\r
169                         }\r
170                         if (complain)\r
171                                 Report.Error (\r
172                                         246, Location, "Could not find attribute '" + Name + "' (are you" +\r
173                                         " missing a using directive or an assembly reference ?)");\r
174                         return null;\r
175                 }\r
176 \r
177                 public Type ResolveType (EmitContext ec, bool complain)\r
178                 {\r
179                         if (Type == null)\r
180                                 Type = CheckAttributeType (ec, complain);\r
181                         return Type;\r
182                 }\r
183 \r
184                 /// <summary>\r
185                 ///   Validates the guid string\r
186                 /// </summary>\r
187                 bool ValidateGuid (string guid)\r
188                 {\r
189                         try {\r
190                                 new Guid (guid);\r
191                                 return true;\r
192                         } catch {\r
193                                 Report.Error (647, Location, "Format of GUID is invalid: " + guid);\r
194                                 return false;\r
195                         }\r
196                 }\r
197 \r
198                 //\r
199                 // Given an expression, if the expression is a valid attribute-argument-expression\r
200                 // returns an object that can be used to encode it, or null on failure.\r
201                 //\r
202                 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)\r
203                 {\r
204                         if (e is Constant) {\r
205                                 result = ((Constant) e).GetValue ();\r
206                                 return true;\r
207                         } else if (e is TypeOf) {\r
208                                 result = ((TypeOf) e).TypeArg;\r
209                                 return true;\r
210                         } else if (e is ArrayCreation){\r
211                                 result =  ((ArrayCreation) e).EncodeAsAttribute ();\r
212                                 if (result != null)\r
213                                         return true;\r
214                         } else if (e is EmptyCast) {\r
215                                 result = e;\r
216                                 if (((EmptyCast) e).Child is Constant) {\r
217                                         result = ((Constant) ((EmptyCast)e).Child).GetValue();\r
218                                 }\r
219                                 return true;\r
220                         }\r
221 \r
222                         result = null;\r
223                         Error_AttributeArgumentNotValid (loc);\r
224                         return false;\r
225                 }\r
226                 \r
227                 public CustomAttributeBuilder Resolve (EmitContext ec)\r
228                 {\r
229                         Type oldType = Type;\r
230 \r
231                         // Sanity check.\r
232                         Type = CheckAttributeType (ec, true);\r
233                         if (oldType == null && Type == null)\r
234                                 return null;\r
235                         if (oldType != null && oldType != Type) {\r
236                                 Report.Error (-6, Location,\r
237                                               "Attribute {0} resolved to different types at different times: {1} vs. {2}",\r
238                                               Name, oldType, Type);\r
239                                 return null;\r
240                         }\r
241 \r
242                         bool MethodImplAttr = false;\r
243                         bool MarshalAsAttr = false;\r
244                         bool GuidAttr = false;\r
245                         bool usage_attr = false;\r
246 \r
247                         bool DoCompares = true;\r
248 \r
249                         //\r
250                         // If we are a certain special attribute, we\r
251                         // set the information accordingly\r
252                         //\r
253                         \r
254                         if (Type == TypeManager.attribute_usage_type)\r
255                                 usage_attr = true;\r
256                         else if (Type == TypeManager.methodimpl_attr_type)\r
257                                 MethodImplAttr = true;\r
258                         else if (Type == TypeManager.marshal_as_attr_type)\r
259                                 MarshalAsAttr = true;\r
260                         else if (Type == TypeManager.guid_attr_type)\r
261                                 GuidAttr = true;\r
262                         else\r
263                                 DoCompares = false;\r
264 \r
265                         // Now we extract the positional and named arguments\r
266                         \r
267                         ArrayList pos_args = new ArrayList ();\r
268                         ArrayList named_args = new ArrayList ();\r
269                         int pos_arg_count = 0;\r
270                         \r
271                         if (Arguments != null) {\r
272                                 pos_args = (ArrayList) Arguments [0];\r
273                                 if (pos_args != null)\r
274                                         pos_arg_count = pos_args.Count;\r
275                                 if (Arguments.Count > 1)\r
276                                         named_args = (ArrayList) Arguments [1];\r
277                         }\r
278 \r
279                         pos_values = new object [pos_arg_count];\r
280 \r
281                         //\r
282                         // First process positional arguments \r
283                         //\r
284 \r
285                         int i;\r
286                         for (i = 0; i < pos_arg_count; i++) {\r
287                                 Argument a = (Argument) pos_args [i];\r
288                                 Expression e;\r
289 \r
290                                 if (!a.Resolve (ec, Location))\r
291                                         return null;\r
292 \r
293                                 e = a.Expr;\r
294 \r
295                                 object val;\r
296                                 if (!GetAttributeArgumentExpression (e, Location, out val))\r
297                                         return null;\r
298                                 \r
299                                 pos_values [i] = val;\r
300                                 if (DoCompares){\r
301                                         if (usage_attr)\r
302                                                 usage_attribute = new AttributeUsageAttribute ((AttributeTargets) pos_values [0]);\r
303                                         else if (MethodImplAttr)\r
304                                                 this.ImplOptions = (MethodImplOptions) pos_values [0];\r
305                                         else if (GuidAttr){\r
306                                                 //\r
307                                                 // we will later check the validity of the type\r
308                                                 //\r
309                                                 if (pos_values [0] is string){\r
310                                                         if (!ValidateGuid ((string) pos_values [0]))\r
311                                                                 return null;\r
312                                                 }\r
313                                                 \r
314                                         } else if (MarshalAsAttr)\r
315                                                 this.UnmanagedType =\r
316                                                 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];\r
317                                 }\r
318                         }\r
319 \r
320                         //\r
321                         // Now process named arguments\r
322                         //\r
323 \r
324                         ArrayList field_infos = null;\r
325                         ArrayList prop_infos  = null;\r
326                         ArrayList field_values = null;\r
327                         ArrayList prop_values = null;\r
328 \r
329                         Hashtable seen_names = new Hashtable();\r
330 \r
331                         if (named_args.Count > 0) {\r
332                                 field_infos = new ArrayList ();\r
333                                 prop_infos  = new ArrayList ();\r
334                                 field_values = new ArrayList ();\r
335                                 prop_values = new ArrayList ();\r
336                         }\r
337                         \r
338                         for (i = 0; i < named_args.Count; i++) {\r
339                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
340                                 string member_name = (string) de.Key;\r
341                                 Argument a  = (Argument) de.Value;\r
342                                 Expression e;\r
343 \r
344                                 if (seen_names.Contains(member_name)) {\r
345                                         Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument");\r
346                                         return null;\r
347                                 }\r
348                                 seen_names.Add(member_name, 1);\r
349 \r
350                                 if (!a.Resolve (ec, Location))\r
351                                         return null;\r
352 \r
353                                 Expression member = Expression.MemberLookup (\r
354                                         ec, Type, member_name,\r
355                                         MemberTypes.Field | MemberTypes.Property,\r
356                                         BindingFlags.Public | BindingFlags.Instance,\r
357                                         Location);\r
358 \r
359                                 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {\r
360                                         Error_InvalidNamedArgument (member_name);\r
361                                         return null;\r
362                                 }\r
363 \r
364                                 e = a.Expr;\r
365                                 if (e is TypeParameterExpr){\r
366                                         Error_TypeParameterInAttribute (Location);\r
367                                         return null;\r
368                                 }\r
369                                         \r
370                                 if (member is PropertyExpr) {\r
371                                         PropertyExpr pe = (PropertyExpr) member;\r
372                                         PropertyInfo pi = pe.PropertyInfo;\r
373 \r
374                                         if (!pi.CanWrite) {\r
375                                                 Error_InvalidNamedArgument (member_name);\r
376                                                 return null;\r
377                                         }\r
378 \r
379                                         if (e is Constant) {\r
380                                                 Constant c;\r
381 \r
382                                                 if (e.Type != pi.PropertyType){\r
383                                                         c = Const.ChangeType (Location, (Constant) e, pi.PropertyType);\r
384                                                         if (c == null)\r
385                                                                 return null;\r
386                                                 } else\r
387                                                         c = (Constant) e;\r
388 \r
389                                                 object o = c.GetValue ();\r
390                                                 prop_values.Add (o);\r
391                                                 \r
392                                                 if (usage_attribute != null) {\r
393                                                         if (member_name == "AllowMultiple")\r
394                                                                 usage_attribute.AllowMultiple = (bool) o;\r
395                                                         if (member_name == "Inherited")\r
396                                                                 usage_attribute.Inherited = (bool) o;\r
397                                                 }\r
398                                                 \r
399                                         } else if (e is TypeOf) {\r
400                                                 prop_values.Add (((TypeOf) e).TypeArg);\r
401                                         } else if (e is ArrayCreation) {\r
402                                                 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());\r
403                                         } else {\r
404                                                 Error_AttributeArgumentNotValid (Location);\r
405                                                 return null;\r
406                                         }\r
407                                         \r
408                                         prop_infos.Add (pi);\r
409                                         \r
410                                 } else if (member is FieldExpr) {\r
411                                         FieldExpr fe = (FieldExpr) member;\r
412                                         FieldInfo fi = fe.FieldInfo;\r
413 \r
414                                         if (fi.IsInitOnly) {\r
415                                                 Error_InvalidNamedArgument (member_name);\r
416                                                 return null;\r
417                                         }\r
418 \r
419                                         //\r
420                                         // Handle charset here, and set the TypeAttributes\r
421                                         \r
422                                         if (e is Constant){\r
423                                                 Constant c = (Constant) e;;\r
424 \r
425                                                 if (c.Type != fi.FieldType){\r
426                                                         c = Const.ChangeType (Location, (Constant) e, fi.FieldType);\r
427                                                         if (c == null)\r
428                                                                 return null;\r
429                                                 }\r
430 \r
431                                                 object value = c.GetValue ();\r
432                                                 field_values.Add (value);\r
433                                         } else if (e is TypeOf) {\r
434                                                 field_values.Add (((TypeOf) e).TypeArg);\r
435                                         } else {\r
436                                                 Error_AttributeArgumentNotValid (Location);\r
437                                                 return null;\r
438                                         }\r
439                                         \r
440                                         field_infos.Add (fi);\r
441                                 }\r
442                         }\r
443 \r
444                         Expression mg = Expression.MemberLookup (\r
445                                 ec, Type, ".ctor", MemberTypes.Constructor,\r
446                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,\r
447                                 Location);\r
448 \r
449                         if (mg == null) {\r
450                                 Error_AttributeConstructorMismatch (Location);\r
451                                 return null;\r
452                         }\r
453 \r
454                         MethodBase constructor = Invocation.OverloadResolve (\r
455                                 ec, (MethodGroupExpr) mg, pos_args, false, Location);\r
456 \r
457                         if (constructor == null) {\r
458                                 Error_AttributeConstructorMismatch (Location);\r
459                                 return null;\r
460                         }\r
461 \r
462                         //\r
463                         // Now we perform some checks on the positional args as they\r
464                         // cannot be null for a constructor which expects a parameter\r
465                         // of type object\r
466                         //\r
467 \r
468                         ParameterData pd = Invocation.GetParameterData (constructor);\r
469 \r
470                         int group_in_params_array = Int32.MaxValue;\r
471                         int pc = pd.Count;\r
472                         if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)\r
473                                 group_in_params_array = pc-1;\r
474                         \r
475                         for (int j = 0; j < pos_arg_count; ++j) {\r
476                                 Argument a = (Argument) pos_args [j];\r
477                                 \r
478                                 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {\r
479                                         Error_AttributeArgumentNotValid (Location);\r
480                                         return null;\r
481                                 }\r
482 \r
483                                 if (j < group_in_params_array)\r
484                                         continue;\r
485                                 \r
486                                 if (j == group_in_params_array){\r
487                                         object v = pos_values [j];\r
488                                         int count = pos_arg_count - j;\r
489 \r
490                                         object [] array = new object [count];\r
491                                         pos_values [j] = array;\r
492                                         array [0] = v;\r
493                                 } else {\r
494                                         object [] array = (object []) pos_values [group_in_params_array];\r
495 \r
496                                         array [j - group_in_params_array] = pos_values [j];\r
497                                 }\r
498                         }\r
499 \r
500                         //\r
501                         // Adjust the size of the pos_values if it had params\r
502                         //\r
503                         if (group_in_params_array != Int32.MaxValue){\r
504                                 int argc = group_in_params_array+1;\r
505                                 object [] new_pos_values = new object [argc];\r
506 \r
507                                 for (int p = 0; p < argc; p++)\r
508                                         new_pos_values [p] = pos_values [p];\r
509                                 pos_values = new_pos_values;\r
510                         }\r
511 \r
512                         try {\r
513                                 if (named_args.Count > 0) {\r
514                                         prop_info_arr = new PropertyInfo [prop_infos.Count];\r
515                                         field_info_arr = new FieldInfo [field_infos.Count];\r
516                                         field_values_arr = new object [field_values.Count];\r
517                                         prop_values_arr = new object [prop_values.Count];\r
518 \r
519                                         field_infos.CopyTo  (field_info_arr, 0);\r
520                                         field_values.CopyTo (field_values_arr, 0);\r
521 \r
522                                         prop_values.CopyTo  (prop_values_arr, 0);\r
523                                         prop_infos.CopyTo   (prop_info_arr, 0);\r
524 \r
525                                         cb = new CustomAttributeBuilder (\r
526                                                 (ConstructorInfo) constructor, pos_values,\r
527                                                 prop_info_arr, prop_values_arr,\r
528                                                 field_info_arr, field_values_arr);\r
529                                 }\r
530                                 else\r
531                                         cb = new CustomAttributeBuilder (\r
532                                                 (ConstructorInfo) constructor, pos_values);\r
533                         } catch (NullReferenceException) {\r
534                                 // \r
535                                 // Don't know what to do here\r
536                                 //\r
537                                 Report.Warning (\r
538                                         -101, Location, "NullReferenceException while trying to create attribute." +\r
539                                         "Something's wrong!");\r
540                         } catch (Exception e) {\r
541                                 //\r
542                                 // Sample:\r
543                                 // using System.ComponentModel;\r
544                                 // [DefaultValue (CollectionChangeAction.Add)]\r
545                                 // class X { static void Main () {} }\r
546                                 //\r
547                                 Report.Warning (\r
548                                         -23, Location,\r
549                                         "The compiler can not encode this attribute in .NET due to\n" +\r
550                                         "\ta bug in the .NET runtime.  Try the Mono runtime.\nThe error was: " + e.Message);\r
551                         }\r
552                         \r
553                         return cb;\r
554                 }\r
555 \r
556                 /// <summary>\r
557                 ///   Get a string containing a list of valid targets for the attribute 'attr'\r
558                 /// </summary>\r
559                 static string GetValidTargets (Attribute attr)\r
560                 {\r
561                         StringBuilder sb = new StringBuilder ();\r
562                         AttributeTargets targets = attr.GetAttributeUsage ().ValidOn;\r
563                         \r
564                         if ((targets & AttributeTargets.Assembly) != 0)\r
565                                 sb.Append ("'assembly' ");\r
566 \r
567                         if ((targets & AttributeTargets.Class) != 0)\r
568                                 sb.Append ("'class' ");\r
569 \r
570                         if ((targets & AttributeTargets.Constructor) != 0)\r
571                                 sb.Append ("'constructor' ");\r
572 \r
573                         if ((targets & AttributeTargets.Delegate) != 0)\r
574                                 sb.Append ("'delegate' ");\r
575 \r
576                         if ((targets & AttributeTargets.Enum) != 0)\r
577                                 sb.Append ("'enum' ");\r
578 \r
579                         if ((targets & AttributeTargets.Event) != 0)\r
580                                 sb.Append ("'event' ");\r
581 \r
582                         if ((targets & AttributeTargets.Field) != 0)\r
583                                 sb.Append ("'field' ");\r
584 \r
585                         if ((targets & AttributeTargets.Interface) != 0)\r
586                                 sb.Append ("'interface' ");\r
587 \r
588                         if ((targets & AttributeTargets.Method) != 0)\r
589                                 sb.Append ("'method' ");\r
590 \r
591                         if ((targets & AttributeTargets.Module) != 0)\r
592                                 sb.Append ("'module' ");\r
593 \r
594                         if ((targets & AttributeTargets.Parameter) != 0)\r
595                                 sb.Append ("'parameter' ");\r
596 \r
597                         if ((targets & AttributeTargets.Property) != 0)\r
598                                 sb.Append ("'property' ");\r
599 \r
600                         if ((targets & AttributeTargets.ReturnValue) != 0)\r
601                                 sb.Append ("'return' ");\r
602 \r
603                         if ((targets & AttributeTargets.Struct) != 0)\r
604                                 sb.Append ("'struct' ");\r
605 \r
606                         return sb.ToString ();\r
607 \r
608                 }\r
609 \r
610                 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)\r
611                 {\r
612                         Report.Error (\r
613                                 592, loc, "Attribute '" + a.Name +\r
614                                 "' is not valid on this declaration type. " +\r
615                                 "It is valid on " + GetValidTargets (a) + "declarations only.");\r
616                 }\r
617 \r
618                 /// <summary>\r
619                 /// Returns AttributeUsage attribute for this type\r
620                 /// </summary>\r
621                 public AttributeUsageAttribute GetAttributeUsage ()\r
622                 {\r
623                         AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute;\r
624                         if (ua != null)\r
625                                 return ua;\r
626 \r
627                         Class attr_class = TypeManager.LookupClass (Type);\r
628 \r
629                         if (attr_class == null) {\r
630                                 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);\r
631                                 ua = (AttributeUsageAttribute)usage_attr [0];\r
632                                 usage_attr_cache.Add (Type, ua);\r
633                                 return ua;\r
634                         }\r
635 \r
636                         return attr_class.AttributeUsage;\r
637                 }\r
638 \r
639                 //\r
640                 // This method should be invoked to pull the IndexerName attribute from an\r
641                 // Indexer if it exists.\r
642                 //\r
643                 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)\r
644                 {\r
645                         if (opt_attrs == null)\r
646                                 return null;\r
647                         if (opt_attrs.AttributeSections == null)\r
648                                 return null;\r
649 \r
650                         foreach (Attribute a in opt_attrs.AttributeSections) {\r
651                                 if (a.ResolveType (ec, true) == null)\r
652                                         return null;\r
653 \r
654                                 if (a.Type != TypeManager.indexer_name_type)\r
655                                         continue;\r
656 \r
657                                 //\r
658                                 // So we have found an IndexerName, pull the data out.\r
659                                 //\r
660                                 if (a.Arguments == null || a.Arguments [0] == null){\r
661                                         Error_AttributeConstructorMismatch (a.Location);\r
662                                         return null;\r
663                                 }\r
664                                 ArrayList pos_args = (ArrayList) a.Arguments [0];\r
665                                 if (pos_args.Count == 0){\r
666                                         Error_AttributeConstructorMismatch (a.Location);\r
667                                         return null;\r
668                                 }\r
669                                         \r
670                                 Argument arg = (Argument) pos_args [0];\r
671                                 if (!arg.Resolve (ec, a.Location))\r
672                                         return null;\r
673                                         \r
674                                 Expression e = arg.Expr;\r
675                                 if (!(e is StringConstant)){\r
676                                         Error_AttributeConstructorMismatch (a.Location);\r
677                                         return null;\r
678                                 }\r
679 \r
680                                 //\r
681                                 // Remove the attribute from the list\r
682                                 //\r
683 \r
684                                 //TODO: It is very close to hack and it can crash here\r
685                                 opt_attrs.AttributeSections.Remove (a);\r
686 \r
687                                 return (((StringConstant) e).Value);\r
688                         }\r
689                         return null;\r
690                 }\r
691 \r
692                 //\r
693                 // This pulls the condition name out of a Conditional attribute\r
694                 //\r
695                 public string Conditional_GetConditionName ()\r
696                 {\r
697                         //\r
698                         // So we have a Conditional, pull the data out.\r
699                         //\r
700                         if (Arguments == null || Arguments [0] == null){\r
701                                 Error_AttributeConstructorMismatch (Location);\r
702                                 return null;\r
703                         }\r
704 \r
705                         ArrayList pos_args = (ArrayList) Arguments [0];\r
706                         if (pos_args.Count != 1){\r
707                                 Error_AttributeConstructorMismatch (Location);\r
708                                 return null;\r
709                         }\r
710 \r
711                         Argument arg = (Argument) pos_args [0]; \r
712                         if (!(arg.Expr is StringConstant)){\r
713                                 Error_AttributeConstructorMismatch (Location);\r
714                                 return null;\r
715                         }\r
716 \r
717                         return ((StringConstant) arg.Expr).Value;\r
718                 }\r
719 \r
720                 //\r
721                 // This pulls the obsolete message and error flag out of an Obsolete attribute\r
722                 //\r
723                 public string Obsolete_GetObsoleteMessage (out bool is_error)\r
724                 {\r
725                         is_error = false;\r
726                         //\r
727                         // So we have an Obsolete, pull the data out.\r
728                         //\r
729                         if (Arguments == null || Arguments [0] == null)\r
730                                 return "";\r
731 \r
732                         ArrayList pos_args = (ArrayList) Arguments [0];\r
733                         if (pos_args.Count == 0)\r
734                                 return "";\r
735                         else if (pos_args.Count > 2){\r
736                                 Error_AttributeConstructorMismatch (Location);\r
737                                 return null;\r
738                         }\r
739 \r
740                         Argument arg = (Argument) pos_args [0]; \r
741                         if (!(arg.Expr is StringConstant)){\r
742                                 Error_AttributeConstructorMismatch (Location);\r
743                                 return null;\r
744                         }\r
745 \r
746                         if (pos_args.Count == 2){\r
747                                 Argument arg2 = (Argument) pos_args [1];\r
748                                 if (!(arg2.Expr is BoolConstant)){\r
749                                         Error_AttributeConstructorMismatch (Location);\r
750                                         return null;\r
751                                 }\r
752                                 is_error = ((BoolConstant) arg2.Expr).Value;\r
753                         }\r
754 \r
755                         return ((StringConstant) arg.Expr).Value;\r
756                 }\r
757 \r
758                 /// <summary>\r
759                 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called\r
760                 /// before ApplyAttribute. We need to resolve the arguments.\r
761                 /// This situation occurs when class deps is differs from Emit order.  \r
762                 /// </summary>\r
763                 public bool GetClsCompliantAttributeValue (DeclSpace ds)\r
764                 {\r
765                         if (pos_values == null) {\r
766                                 EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);\r
767 \r
768                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.\r
769                                 // But because a lot of attribute class code must be rewritten will be better to wait...\r
770 \r
771                                 Resolve (ec);\r
772                         }\r
773 \r
774                         // Some error occurred\r
775                         if (pos_values [0] == null)\r
776                                 return false;\r
777 \r
778                         return (bool)pos_values [0];\r
779                 }\r
780 \r
781                 public object GetPositionalValue (int i)\r
782                 {\r
783                         return (pos_values == null) ? null : pos_values[i];\r
784                 }\r
785 \r
786                 object GetFieldValue (string name)\r
787                 {\r
788                         int i;\r
789                         if (field_info_arr == null)\r
790                                 return null;\r
791                         i = 0;\r
792                         foreach (FieldInfo fi in field_info_arr) {\r
793                                 if (fi.Name == name)\r
794                                         return field_values_arr [i];\r
795                                 i++;\r
796                         }\r
797                         return null;\r
798                 }\r
799 \r
800                 public UnmanagedMarshal GetMarshal ()\r
801                 {\r
802                         object o = GetFieldValue ("ArraySubType");\r
803                         UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;\r
804                         switch (UnmanagedType) {\r
805                         case UnmanagedType.CustomMarshaler:\r
806                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",\r
807                                                                        BindingFlags.Static | BindingFlags.Public);\r
808                                 if (define_custom == null)\r
809                                         return null;\r
810 \r
811                                 object [] args = new object [4];\r
812                                 args [0] = GetFieldValue ("MarshalTypeRef");\r
813                                 args [1] = GetFieldValue ("MarshalCookie");\r
814                                 args [2] = GetFieldValue ("MarshalType");\r
815                                 args [3] = Guid.Empty;\r
816                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);\r
817 \r
818                         case UnmanagedType.LPArray:                             \r
819                                 return UnmanagedMarshal.DefineLPArray (array_sub_type);\r
820 \r
821                         case UnmanagedType.SafeArray:\r
822                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);\r
823 \r
824                         case UnmanagedType.ByValArray:\r
825                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));\r
826 \r
827                         case UnmanagedType.ByValTStr:\r
828                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));\r
829 \r
830                         default:\r
831                                 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);\r
832                         }\r
833                 }\r
834 \r
835                 public bool IsInternalCall\r
836                 {\r
837                         get { return ImplOptions == MethodImplOptions.InternalCall; }\r
838                 }\r
839 \r
840                 /// <summary>\r
841                 /// Emit attribute for Attributable symbol\r
842                 /// </summary>\r
843                 public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr)\r
844                 {\r
845                         CustomAttributeBuilder cb = Resolve (ec);\r
846                         if (cb == null) \r
847                                 return;\r
848 \r
849                         AttributeUsageAttribute usage_attr = GetAttributeUsage ();\r
850                         if ((usage_attr.ValidOn & ias.AttributeTargets) == 0) {\r
851                                 Error_AttributeNotValidForElement (this, Location);\r
852                                 return;\r
853                         }\r
854 \r
855                         ias.ApplyAttributeBuilder (this, cb);\r
856 \r
857                         string emitted = emitted_attr [Type] as string;\r
858                         if (Target != null && emitted == Target && !usage_attr.AllowMultiple) {\r
859                                 Report.Error (579, Location, "Duplicate '" + Name + "' attribute");\r
860                         }\r
861 \r
862                         emitted_attr [Type] = Target;\r
863 \r
864                         // Here we are testing attribute arguments for array usage (error 3016)\r
865                         if (ias.IsClsCompliaceRequired (ec.DeclSpace)) {\r
866                                 if (Arguments == null)\r
867                                         return;\r
868 \r
869                                 ArrayList pos_args = (ArrayList) Arguments [0];\r
870 \r
871                                 if (pos_args != null) {\r
872                                         foreach (Argument arg in pos_args) { \r
873                                                 // Type is undefined (was error 246)\r
874                                                 if (arg.Type == null)\r
875                                                         return;\r
876 \r
877                                                 if (arg.Type.IsArray) {\r
878                                                         Report.Error_T (3016, Location);\r
879                                                         return;\r
880                                                 }\r
881                                         }\r
882                                 }\r
883 \r
884                                 if (Arguments.Count < 2)\r
885                                         return;\r
886 \r
887                                 ArrayList named_args = (ArrayList) Arguments [1];\r
888 \r
889                                 foreach (DictionaryEntry de in named_args) {\r
890                                         Argument arg  = (Argument) de.Value;\r
891 \r
892                                         // Type is undefined (was error 246)\r
893                                         if (arg.Type == null)\r
894                                                 return;\r
895 \r
896                                         if (arg.Type.IsArray) {\r
897                                                 Report.Error_T (3016, Location);\r
898                                                 return;\r
899                                         }\r
900                                 }\r
901                         }\r
902                 }\r
903 \r
904                 public object GetValue (EmitContext ec, Constant c, Type target)\r
905                 {\r
906                         if (Convert.ImplicitConversionExists (ec, c, target))\r
907                                 return c.GetValue ();\r
908 \r
909                         Convert.Error_CannotImplicitConversion (Location, c.Type, target);\r
910                         return null;\r
911                 }\r
912 \r
913                 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,\r
914                                                           MethodAttributes flags, Type ret_type, Type [] param_types)\r
915                 {\r
916                         //\r
917                         // We extract from the attribute the information we need \r
918                         //\r
919 \r
920                         if (Arguments == null) {\r
921                                 Console.WriteLine ("Internal error : this is not supposed to happen !");\r
922                                 return null;\r
923                         }\r
924 \r
925                         ResolveType (ec, true);\r
926                         if (Type == null)\r
927                                 return null;\r
928                         \r
929                         ArrayList named_args = new ArrayList ();\r
930                         \r
931                         ArrayList pos_args = (ArrayList) Arguments [0];\r
932                         if (Arguments.Count > 1)\r
933                                 named_args = (ArrayList) Arguments [1];\r
934                         \r
935 \r
936                         string dll_name = null;\r
937                         \r
938                         Argument tmp = (Argument) pos_args [0];\r
939 \r
940                         if (!tmp.Resolve (ec, Location))\r
941                                 return null;\r
942                         \r
943                         if (tmp.Expr is Constant)\r
944                                 dll_name = (string) ((Constant) tmp.Expr).GetValue ();\r
945                         else { \r
946                                 Error_AttributeArgumentNotValid (Location);\r
947                                 return null;\r
948                         }\r
949 \r
950                         // Now we process the named arguments\r
951                         CallingConvention cc = CallingConvention.Winapi;\r
952                         CharSet charset = CharSet.Ansi;\r
953                         bool preserve_sig = true;\r
954 #if FIXME\r
955                         bool exact_spelling = false;\r
956 #endif\r
957                         bool set_last_err = false;\r
958                         string entry_point = null;\r
959 \r
960                         for (int i = 0; i < named_args.Count; i++) {\r
961 \r
962                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
963 \r
964                                 string member_name = (string) de.Key;\r
965                                 Argument a  = (Argument) de.Value;\r
966 \r
967                                 if (!a.Resolve (ec, Location))\r
968                                         return null;\r
969 \r
970                                 Expression member = Expression.MemberLookup (\r
971                                         ec, Type, member_name, \r
972                                         MemberTypes.Field | MemberTypes.Property,\r
973                                         BindingFlags.Public | BindingFlags.Instance,\r
974                                         Location);\r
975 \r
976                                 if (member == null || !(member is FieldExpr)) {\r
977                                         Error_InvalidNamedArgument (member_name);\r
978                                         return null;\r
979                                 }\r
980 \r
981                                 if (member is FieldExpr) {\r
982                                         FieldExpr fe = (FieldExpr) member;\r
983                                         FieldInfo fi = fe.FieldInfo;\r
984 \r
985                                         if (fi.IsInitOnly) {\r
986                                                 Error_InvalidNamedArgument (member_name);\r
987                                                 return null;\r
988                                         }\r
989 \r
990                                         if (a.Expr is Constant) {\r
991                                                 Constant c = (Constant) a.Expr;\r
992 \r
993                                                 try {\r
994                                                         if (member_name == "CallingConvention"){\r
995                                                                 object val = GetValue (ec, c, typeof (CallingConvention));\r
996                                                                 if (val == null)\r
997                                                                         return null;\r
998                                                                 cc = (CallingConvention) val;\r
999                                                         } else if (member_name == "CharSet"){\r
1000                                                                 charset = (CharSet) c.GetValue ();\r
1001                                                         } else if (member_name == "EntryPoint")\r
1002                                                                 entry_point = (string) c.GetValue ();\r
1003                                                         else if (member_name == "SetLastError")\r
1004                                                                 set_last_err = (bool) c.GetValue ();\r
1005 #if FIXME\r
1006                                                         else if (member_name == "ExactSpelling")\r
1007                                                                 exact_spelling = (bool) c.GetValue ();\r
1008 #endif\r
1009                                                         else if (member_name == "PreserveSig")\r
1010                                                                 preserve_sig = (bool) c.GetValue ();\r
1011                                                 } catch (InvalidCastException){\r
1012                                                         Error_InvalidNamedArgument (member_name);\r
1013                                                         Error_AttributeArgumentNotValid (Location);\r
1014                                                 }\r
1015                                         } else { \r
1016                                                 Error_AttributeArgumentNotValid (Location);\r
1017                                                 return null;\r
1018                                         }\r
1019                                         \r
1020                                 }\r
1021                         }\r
1022 \r
1023                         if (entry_point == null)\r
1024                                 entry_point = name;\r
1025                         if (set_last_err)\r
1026                                 charset = (CharSet)((int)charset | 0x40);\r
1027                         \r
1028                         MethodBuilder mb = builder.DefinePInvokeMethod (\r
1029                                 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,\r
1030                                 CallingConventions.Standard,\r
1031                                 ret_type,\r
1032                                 param_types,\r
1033                                 cc,\r
1034                                 charset);\r
1035 \r
1036                         if (preserve_sig)\r
1037                                 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);\r
1038                         \r
1039                         return mb;\r
1040                 }\r
1041 \r
1042                 private Expression GetValue () \r
1043                 {\r
1044                         if ((Arguments == null) || (Arguments.Count < 1))\r
1045                                 return null;\r
1046                         ArrayList al = (ArrayList) Arguments [0];\r
1047                         if ((al == null) || (al.Count < 1))\r
1048                                 return null;\r
1049                         Argument arg = (Argument) al [0];\r
1050                         if ((arg == null) || (arg.Expr == null))\r
1051                                 return null;\r
1052                         return arg.Expr;\r
1053                 }\r
1054 \r
1055                 public string GetString () \r
1056                 {\r
1057                         Expression e = GetValue ();\r
1058                         if (e is StringLiteral)\r
1059                                 return (e as StringLiteral).Value;\r
1060                         return null;\r
1061                 }\r
1062 \r
1063                 public bool GetBoolean () \r
1064                 {\r
1065                         Expression e = GetValue ();\r
1066                         if (e is BoolLiteral)\r
1067                                 return (e as BoolLiteral).Value;\r
1068                         return false;\r
1069                 }\r
1070         }\r
1071         \r
1072         /// For global attributes (assembly, module) we need special handling.\r
1073         /// Attributes can be located in the several files\r
1074         /// </summary>\r
1075         public class GlobalAttribute: Attribute\r
1076         {\r
1077                 public readonly NamespaceEntry ns;\r
1078 \r
1079                 public GlobalAttribute (TypeContainer container, string target, string name, ArrayList args, Location loc):\r
1080                         base (target, name, args, loc)\r
1081                 {\r
1082                         ns = container.NamespaceEntry;\r
1083                 }\r
1084 \r
1085                 protected override Type CheckAttributeType (EmitContext ec, bool complain)\r
1086                 {\r
1087                         ec.DeclSpace.NamespaceEntry = ns;\r
1088                         return base.CheckAttributeType (ec, complain);\r
1089                 }\r
1090         }\r
1091 \r
1092         public class Attributes {\r
1093                 public ArrayList AttributeSections;\r
1094 \r
1095                 public Attributes (Attribute a)\r
1096                 {\r
1097                         AttributeSections = new ArrayList ();\r
1098                         AttributeSections.Add (a);\r
1099                 }\r
1100 \r
1101                 public Attributes (ArrayList attrs)\r
1102                 {\r
1103                         AttributeSections = attrs;\r
1104                 }\r
1105 \r
1106                 public void AddAttributes (ArrayList attrs)\r
1107                 {\r
1108                         AttributeSections.AddRange (attrs);\r
1109                 }\r
1110 \r
1111                 /// <summary>\r
1112                 /// Checks whether attribute target is valid for the current element\r
1113                 /// </summary>\r
1114                 public void CheckTargets (string[] possible_targets)\r
1115                 {\r
1116                         foreach (Attribute a in AttributeSections) {\r
1117                                 if (a.Target == null)\r
1118                                         continue;\r
1119 \r
1120                                 bool valid_target = false;\r
1121                                 for (int i = 0; i < possible_targets.Length; ++i) {\r
1122                                         if (a.Target == possible_targets [i]) {\r
1123                                                 valid_target = true;\r
1124                                                 break;\r
1125                                         }\r
1126                                 }\r
1127 \r
1128                                 if (valid_target)\r
1129                                         continue;\r
1130 \r
1131                                 StringBuilder sb = new StringBuilder ();\r
1132                                 foreach (string s in possible_targets) {\r
1133                                         sb.Append (s);\r
1134                                         sb.Append (", ");\r
1135                                 }\r
1136                                 sb.Remove (sb.Length - 2, 2);\r
1137                                 Report.Error_T (657, a.Location, a.Target, sb.ToString ());\r
1138                         }\r
1139                 }\r
1140 \r
1141                 public Attribute Search (Type t, EmitContext ec)\r
1142                 {\r
1143                         foreach (Attribute attr_section in AttributeSections) {\r
1144                                 if (attr_section.ResolveType (ec, false) == t)\r
1145                                         return attr_section;\r
1146                         }\r
1147                         return null;\r
1148                 }\r
1149 \r
1150                 public void Emit (EmitContext ec, Attributable ias)\r
1151                 {\r
1152                         ListDictionary ld = new ListDictionary ();\r
1153 \r
1154                         foreach (Attribute a in AttributeSections) {\r
1155                                 a.Emit (ec, ias, ld);\r
1156                         }\r
1157                 }\r
1158 \r
1159                 public bool Contains (Type t, EmitContext ec)\r
1160                 {\r
1161                         return Search (t, ec) != null;\r
1162                 }\r
1163 \r
1164                 public Attribute GetClsCompliantAttribute (EmitContext ec)\r
1165                 {\r
1166                         return Search (TypeManager.cls_compliant_attribute_type, ec);\r
1167                 }\r
1168         }\r
1169 \r
1170         /// <summary>\r
1171         /// Helper class for attribute verification routine.\r
1172         /// </summary>\r
1173         sealed class AttributeTester\r
1174         {\r
1175                 static PtrHashtable analyzed_types = new PtrHashtable ();\r
1176 \r
1177                 private AttributeTester ()\r
1178                 {\r
1179                 }\r
1180 \r
1181                 /// <summary>\r
1182                 /// Returns true if parameters of two compared methods are CLS-Compliant.\r
1183                 /// It tests differing only in ref or out, or in array rank.\r
1184                 /// </summary>\r
1185                 public static bool AreOverloadedMethodParamsClsCompliant (Type[] types_a, Type[] types_b) \r
1186                 {\r
1187                         if (types_a == null || types_b == null)\r
1188                                 return true;\r
1189 \r
1190                         if (types_a.Length != types_b.Length)\r
1191                                 return true;\r
1192 \r
1193                         for (int i = 0; i < types_b.Length; ++i) {\r
1194                                 Type aType = types_a [i];\r
1195                                 Type bType = types_b [i];\r
1196 \r
1197                                 if (aType.IsArray && bType.IsArray && aType.GetArrayRank () != bType.GetArrayRank () && aType.GetElementType () == bType.GetElementType ()) {\r
1198                                         return false;\r
1199                                 }\r
1200 \r
1201                                 Type aBaseType = aType;\r
1202                                 bool is_either_ref_or_out = false;\r
1203 \r
1204                                 if (aType.IsByRef || aType.IsPointer) {\r
1205                                         aBaseType = aType.GetElementType ();\r
1206                                         is_either_ref_or_out = true;\r
1207                                 }\r
1208 \r
1209                                 Type bBaseType = bType;\r
1210                                 if (bType.IsByRef || bType.IsPointer) \r
1211                                 {\r
1212                                         bBaseType = bType.GetElementType ();\r
1213                                         is_either_ref_or_out = !is_either_ref_or_out;\r
1214                                 }\r
1215 \r
1216                                 if (aBaseType != bBaseType)\r
1217                                         continue;\r
1218 \r
1219                                 if (is_either_ref_or_out)\r
1220                                         return false;\r
1221                         }\r
1222                         return true;\r
1223                 }\r
1224 \r
1225                 /// <summary>\r
1226                 /// Goes through all parameters and test if they are CLS-Compliant.\r
1227                 /// </summary>\r
1228                 public static bool AreParametersCompliant (Parameter[] fixedParameters, Location loc)\r
1229                 {\r
1230                         if (fixedParameters == null)\r
1231                                 return true;\r
1232 \r
1233                         foreach (Parameter arg in fixedParameters) {\r
1234                                 if (!AttributeTester.IsClsCompliant (arg.ParameterType)) {\r
1235                                         Report.Error_T (3001, loc, arg.GetSignatureForError ());\r
1236                                         return false;\r
1237                                 }\r
1238                         }\r
1239                         return true;\r
1240                 }\r
1241 \r
1242 \r
1243                 /// <summary>\r
1244                 /// This method tests the CLS compliance of external types. It doesn't test type visibility.\r
1245                 /// </summary>\r
1246                 public static bool IsClsCompliant (Type type) \r
1247                 {\r
1248                         if (type == null)\r
1249                                 return true;\r
1250 \r
1251                         object type_compliance = analyzed_types[type];\r
1252                         if (type_compliance != null)\r
1253                                 return type_compliance == TRUE;\r
1254 \r
1255                         if (type.IsPointer) {\r
1256                                 analyzed_types.Add (type, null);\r
1257                                 return false;\r
1258                         }\r
1259 \r
1260                         bool result;\r
1261                         if (type.IsArray || type.IsByRef)       {\r
1262                                 result = IsClsCompliant (TypeManager.GetElementType (type));\r
1263                         } else {\r
1264                                 result = AnalyzeTypeCompliance (type);\r
1265                         }\r
1266                         analyzed_types.Add (type, result ? TRUE : FALSE);\r
1267                         return result;\r
1268                 }                \r
1269 \r
1270                 static object TRUE = new object ();\r
1271                 static object FALSE = new object ();\r
1272 \r
1273                 /// <summary>\r
1274                 /// Non-hierarchical CLS Compliance analyzer\r
1275                 /// </summary>\r
1276                 public static bool IsComplianceRequired (MemberInfo mi, DeclSpace ds)\r
1277                 {\r
1278                         DeclSpace temp_ds = TypeManager.LookupDeclSpace (mi.DeclaringType);\r
1279 \r
1280                         // Type is external, we can get attribute directly\r
1281                         if (temp_ds == null) {\r
1282                                 object[] cls_attribute = mi.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);\r
1283                                 return (cls_attribute.Length == 1 && ((CLSCompliantAttribute)cls_attribute[0]).IsCompliant);\r
1284                         }\r
1285 \r
1286                         string tmp_name;\r
1287                         // Interface doesn't store full name\r
1288                         if (temp_ds is Interface)\r
1289                                 tmp_name = mi.Name;\r
1290                         else\r
1291                                 tmp_name = String.Concat (temp_ds.Name, ".", mi.Name);\r
1292 \r
1293                         MemberCore mc = temp_ds.GetDefinition (tmp_name) as MemberCore;\r
1294                         return mc.IsClsCompliaceRequired (ds);\r
1295                 }\r
1296 \r
1297                 public static void VerifyModulesClsCompliance ()\r
1298                 {\r
1299                         Module[] modules = TypeManager.Modules;\r
1300                         if (modules == null)\r
1301                                 return;\r
1302 \r
1303                         // The first module is generated assembly\r
1304                         for (int i = 1; i < modules.Length; ++i) {\r
1305                                 Module module = modules [i];\r
1306                                 if (!IsClsCompliant (module)) {\r
1307                                         Report.Error_T (3013, module.Name);\r
1308                                         return;\r
1309                                 }\r
1310                         }\r
1311                 }\r
1312 \r
1313                 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider) \r
1314                 {\r
1315                         object[] CompliantAttribute = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);\r
1316                         if (CompliantAttribute.Length == 0)\r
1317                                 return false;\r
1318 \r
1319                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;\r
1320                 }\r
1321 \r
1322                 static bool AnalyzeTypeCompliance (Type type)\r
1323                 {\r
1324                         DeclSpace ds = TypeManager.LookupDeclSpace (type);\r
1325                         if (ds != null) {\r
1326                                 return ds.IsClsCompliaceRequired (ds.Parent);\r
1327                         }\r
1328 \r
1329                         if (type.IsGenericParameter)\r
1330                                 return false;\r
1331 \r
1332                         object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);\r
1333                         if (CompliantAttribute.Length == 0) \r
1334                                 return IsClsCompliant (type.Assembly);\r
1335 \r
1336                         return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;\r
1337                 }\r
1338         }\r
1339 }\r