Nothing to see here
[mono.git] / mcs / mcs / attribute.cs
1 //
2 // attribute.cs: Attribute Handler
3 //
4 // Author: Ravi Pratap (ravi@ximian.com)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 //
12
13 using System;
14 using System.Diagnostics;
15 using System.Collections;
16 using System.Collections.Specialized;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Runtime.InteropServices;
20 using System.Runtime.CompilerServices;
21 using System.Security; 
22 using System.Security.Permissions;
23 using System.Text;
24 using System.IO;
25
26 namespace Mono.CSharp {
27
28         /// <summary>
29         ///   Base class for objects that can have Attributes applied to them.
30         /// </summary>
31         public abstract class Attributable {
32                 /// <summary>
33                 ///   Attributes for this type
34                 /// </summary>
35                 protected Attributes attributes;
36
37                 public Attributable (Attributes attrs)
38                 {
39                         if (attrs != null)
40                                 OptAttributes = attrs;
41                 }
42
43                 public Attributes OptAttributes 
44                 {
45                         get {
46                                 return attributes;
47                         }
48                         set {
49                                 attributes = value;
50
51                                 if (attributes != null) {
52                                         attributes.AttachTo (this);
53                                 }
54                         }
55                 }
56
57                 /// <summary>
58                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
59                 /// </summary>
60                 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
61
62                 /// <summary>
63                 /// Returns one AttributeTarget for this element.
64                 /// </summary>
65                 public abstract AttributeTargets AttributeTargets { get; }
66
67                 public abstract IResolveContext ResolveContext { get; }
68
69                 public abstract bool IsClsComplianceRequired ();
70
71                 /// <summary>
72                 /// Gets list of valid attribute targets for explicit target declaration.
73                 /// The first array item is default target. Don't break this rule.
74                 /// </summary>
75                 public abstract string[] ValidAttributeTargets { get; }
76         };
77
78         public class Attribute : Expression
79         {
80                 public readonly string ExplicitTarget;
81                 public AttributeTargets Target;
82
83                 // TODO: remove this member
84                 public readonly string    Name;
85                 public readonly Expression LeftExpr;
86                 public readonly string Identifier;
87
88                 ArrayList PosArguments;
89                 ArrayList NamedArguments;
90
91                 bool resolve_error;
92                 readonly bool nameEscaped;
93
94                 // It can contain more onwers when the attribute is applied to multiple fiels.
95                 protected Attributable[] owners;
96
97                 static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
98                 static Assembly orig_sec_assembly;
99                 public static readonly object[] EmptyObject = new object [0];
100
101                 // non-null if named args present after Resolve () is called
102                 PropertyInfo [] prop_info_arr;
103                 FieldInfo [] field_info_arr;
104                 object [] field_values_arr;
105                 object [] prop_values_arr;
106                 object [] pos_values;
107
108                 static PtrHashtable usage_attr_cache;
109                 // Cache for parameter-less attributes
110                 static PtrHashtable att_cache;
111                 
112                 public Attribute (string target, Expression left_expr, string identifier, object[] args, Location loc, bool nameEscaped)
113                 {
114                         LeftExpr = left_expr;
115                         Identifier = identifier;
116                         Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier;
117                         if (args != null) {
118                                 PosArguments = (ArrayList)args [0];
119                                 NamedArguments = (ArrayList)args [1];                           
120                         }
121                         this.loc = loc;
122                         ExplicitTarget = target;
123                         this.nameEscaped = nameEscaped;
124                 }
125
126                 public Attribute Clone ()
127                 {
128                         Attribute a = new Attribute (ExplicitTarget, LeftExpr, Identifier, null, loc, nameEscaped);
129                         a.PosArguments = PosArguments;
130                         a.NamedArguments = NamedArguments;
131                         return a;
132                 }
133
134                 static Attribute ()
135                 {
136                         Reset ();
137                 }
138
139                 public static void Reset ()
140                 {
141                         usage_attr_cache = new PtrHashtable ();
142                         att_cache = new PtrHashtable ();
143                 }
144
145                 public virtual void AttachTo (Attributable owner)
146                 {
147                         if (this.owners == null) {
148                                 this.owners = new Attributable[1] { owner };
149                                 return;
150                         }
151
152                         // When the same attribute is attached to multiple fiels
153                         // we use this extra_owners as a list of owners. The attribute
154                         // then can be removed because will be emitted when first owner
155                         // is served
156                         Attributable[] new_array = new Attributable [this.owners.Length + 1];
157                         owners.CopyTo (new_array, 0);
158                         new_array [owners.Length] = owner;
159                         this.owners = new_array;
160                         owner.OptAttributes = null;
161                 }
162
163                 void Error_InvalidNamedArgument (string name)
164                 {
165                         Report.Error (617, Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
166                                       "must be fields which are not readonly, static, const or read-write properties which are " +
167                                       "public and not static",
168                               name);
169                 }
170
171                 void Error_InvalidNamedAgrumentType (string name)
172                 {
173                         Report.Error (655, Location, "`{0}' is not a valid named attribute argument because it is not a valid " +
174                                       "attribute parameter type", name);
175                 }
176
177                 public static void Error_AttributeArgumentNotValid (Location loc)
178                 {
179                         Report.Error (182, loc,
180                                       "An attribute argument must be a constant expression, typeof " +
181                                       "expression or array creation expression");
182                 }
183                 
184                 static void Error_TypeParameterInAttribute (Location loc)
185                 {
186                         Report.Error (
187                                 -202, loc, "Can not use a type parameter in an attribute");
188                 }
189
190                 public void Error_MissingGuidAttribute ()
191                 {
192                         Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
193                 }
194
195                 public void Error_MisusedExtensionAttribute ()
196                 {
197                         Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
198                 }
199
200                 /// <summary>
201                 /// This is rather hack. We report many emit attribute error with same error to be compatible with
202                 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
203                 /// </summary>
204                 public void Error_AttributeEmitError (string inner)
205                 {
206                         Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
207                                       TypeManager.CSharpName (Type), inner);
208                 }
209
210                 public void Error_InvalidSecurityParent ()
211                 {
212                         Error_AttributeEmitError ("it is attached to invalid parent");
213                 }
214
215                 Attributable Owner {
216                         get {
217                                 return owners [0];
218                         }
219                 }
220
221                 protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent)
222                 {
223                         return expr.ResolveAsTypeTerminal (ec, silent);
224                 }
225
226                 Type ResolvePossibleAttributeType (string name, bool silent, ref bool is_attr)
227                 {
228                         IResolveContext rc = Owner.ResolveContext;
229
230                         TypeExpr te;
231                         if (LeftExpr == null) {
232                                 te = ResolveAsTypeTerminal (new SimpleName (name, Location), rc, silent);
233                         } else {
234                                 te = ResolveAsTypeTerminal (new MemberAccess (LeftExpr, name), rc, silent);
235                         }
236
237                         if (te == null)
238                                 return null;
239
240                         Type t = te.Type;
241                         if (TypeManager.IsSubclassOf (t, TypeManager.attribute_type)) {
242                                 is_attr = true;
243                         } else if (!silent) {
244                                 Report.SymbolRelatedToPreviousError (t);
245                                 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
246                         }
247                         return t;
248                 }
249
250                 /// <summary>
251                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
252                 /// </summary>
253                 void ResolveAttributeType ()
254                 {
255                         bool t1_is_attr = false;
256                         Type t1 = ResolvePossibleAttributeType (Identifier, true, ref t1_is_attr);
257
258                         bool t2_is_attr = false;
259                         Type t2 = nameEscaped ? null :
260                                 ResolvePossibleAttributeType (Identifier + "Attribute", true, ref t2_is_attr);
261
262                         if (t1_is_attr && t2_is_attr) {
263                                 Report.Error (1614, Location, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
264                                               "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
265                                 resolve_error = true;
266                                 return;
267                         }
268
269                         if (t1_is_attr) {
270                                 Type = t1;
271                                 return;
272                         }
273
274                         if (t2_is_attr) {
275                                 Type = t2;
276                                 return;
277                         }
278
279                         if (t1 == null && t2 == null)
280                                 ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr);
281                         if (t1 != null)
282                                 ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr);
283                         if (t2 != null)
284                                 ResolvePossibleAttributeType (Identifier + "Attribute", false, ref t2_is_attr);
285
286                         resolve_error = true;
287                 }
288
289                 public virtual Type ResolveType ()
290                 {
291                         if (Type == null && !resolve_error)
292                                 ResolveAttributeType ();
293                         return Type;
294                 }
295
296                 public override string GetSignatureForError ()
297                 {
298                         if (Type != null)
299                                 return TypeManager.CSharpName (Type);
300
301                         return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier;
302                 }
303
304                 public bool HasSecurityAttribute {
305                         get {
306                                 return TypeManager.security_attr_type != null &&
307                                 TypeManager.IsSubclassOf (type, TypeManager.security_attr_type);
308                         }
309                 }
310
311                 public bool IsValidSecurityAttribute ()
312                 {
313                         return HasSecurityAttribute && IsSecurityActionValid (false);
314                 }
315
316                 static bool IsValidArgumentType (Type t)
317                 {
318                         if (t.IsArray)
319                                 t = TypeManager.GetElementType (t);
320
321                         return t == TypeManager.string_type ||
322                                 TypeManager.IsPrimitiveType (t) ||
323                                 TypeManager.IsEnumType (t) ||
324                                 t == TypeManager.object_type ||
325                                 t == TypeManager.type_type;
326                 }
327
328                 [Conditional ("GMCS_SOURCE")]
329                 void ApplyModuleCharSet ()
330                 {
331                         if (Type != TypeManager.dllimport_type)
332                                 return;
333
334                         if (!CodeGen.Module.HasDefaultCharSet)
335                                 return;
336
337                         const string CharSetEnumMember = "CharSet";
338                         if (NamedArguments == null) {
339                                 NamedArguments = new ArrayList (1);
340                         } else {
341                                 foreach (DictionaryEntry de in NamedArguments) {
342                                         if ((string)de.Key == CharSetEnumMember)
343                                                 return;
344                                 }
345                         }
346                         
347                         NamedArguments.Add (new DictionaryEntry (CharSetEnumMember,
348                                 new Argument (Constant.CreateConstant (typeof (CharSet), CodeGen.Module.DefaultCharSet, Location))));
349                 }
350
351                 public CustomAttributeBuilder Resolve ()
352                 {
353                         if (resolve_error)
354                                 return null;
355
356                         resolve_error = true;
357
358                         if (Type == null) {
359                                 ResolveAttributeType ();
360                                 if (Type == null)
361                                         return null;
362                         }
363
364                         if (Type.IsAbstract) {
365                                 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
366                                 return null;
367                         }
368
369                         ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (Type);
370                         if (obsolete_attr != null) {
371                                 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location);
372                         }
373
374                         if (PosArguments == null && NamedArguments == null) {
375                                 object o = att_cache [Type];
376                                 if (o != null) {
377                                         resolve_error = false;
378                                         return (CustomAttributeBuilder)o;
379                                 }
380                         }
381
382                         Attributable owner = Owner;
383                         DeclSpace ds = owner.ResolveContext as DeclSpace;
384                         if (ds == null)
385                                 ds = owner.ResolveContext.DeclContainer;
386                         
387                         EmitContext ec = new EmitContext (owner.ResolveContext, ds, owner.ResolveContext.DeclContainer,
388                                 Location, null, typeof (Attribute), owner.ResolveContext.DeclContainer.ModFlags, false);
389                         ec.IsAnonymousMethodAllowed = false;
390
391                         ConstructorInfo ctor = ResolveConstructor (ec);
392                         if (ctor == null) {
393                                 if (Type is TypeBuilder && 
394                                     TypeManager.LookupDeclSpace (Type).MemberCache == null)
395                                         // The attribute type has been DefineType'd, but not Defined.  Let's not treat it as an error.
396                                         // It'll be resolved again when the attached-to entity is emitted.
397                                         resolve_error = false;
398                                 return null;
399                         }
400
401                         ApplyModuleCharSet ();
402
403                         CustomAttributeBuilder cb;
404                         try {
405                                 // SRE does not allow private ctor but we want to report all source code errors
406                                 if (ctor.IsPrivate)
407                                         return null;
408
409                                 if (NamedArguments == null) {
410                                         cb = new CustomAttributeBuilder (ctor, pos_values);
411
412                                         if (pos_values.Length == 0)
413                                                 att_cache.Add (Type, cb);
414
415                                         resolve_error = false;
416                                         return cb;
417                                 }
418
419                                 if (!ResolveNamedArguments (ec)) {
420                                         return null;
421                                 }
422
423                                 cb = new CustomAttributeBuilder (ctor, pos_values,
424                                                 prop_info_arr, prop_values_arr,
425                                                 field_info_arr, field_values_arr);
426
427                                 resolve_error = false;
428                                 return cb;
429                         }
430                         catch (Exception) {
431                                 Error_AttributeArgumentNotValid (Location);
432                                 return null;
433                         }
434                 }
435
436                 protected virtual ConstructorInfo ResolveConstructor (EmitContext ec)
437                 {
438                         if (PosArguments != null) {
439                                 for (int i = 0; i < PosArguments.Count; i++) {
440                                         Argument a = (Argument) PosArguments [i];
441
442                                         if (!a.Resolve (ec, Location))
443                                                 return null;
444                                 }
445                         }
446                         
447                         MethodGroupExpr mg = MemberLookupFinal (ec, ec.ContainerType,
448                                 Type, ".ctor", MemberTypes.Constructor,
449                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
450                                 Location) as MethodGroupExpr;
451
452                         if (mg == null)
453                                 return null;
454
455                         mg = mg.OverloadResolve (ec, ref PosArguments, false, Location);
456                         if (mg == null)
457                                 return null;
458                         
459                         ConstructorInfo constructor = (ConstructorInfo)mg;
460                         if (PosArguments == null) {
461                                 pos_values = EmptyObject;
462                                 return constructor;
463                         }
464
465                         AParametersCollection pd = TypeManager.GetParameterData (constructor);
466
467                         int pos_arg_count = PosArguments.Count;
468                         pos_values = new object [pos_arg_count];
469                         for (int j = 0; j < pos_arg_count; ++j) {
470                                 Argument a = (Argument) PosArguments [j];
471
472                                 if (!a.Expr.GetAttributableValue (ec, a.Type, out pos_values [j]))
473                                         return null;
474                         }
475
476                         // Here we do the checks which should be done by corlib or by runtime.
477                         // However Zoltan doesn't like it and every Mono compiler has to do it again.
478                         
479                         if (Type == TypeManager.guid_attr_type) {
480                                 try {
481                                         new Guid ((string)pos_values [0]);
482                                 }
483                                 catch (Exception e) {
484                                         Error_AttributeEmitError (e.Message);
485                                         return null;
486                                 }
487                         }
488
489                         if (Type == TypeManager.attribute_usage_type && (int)pos_values [0] == 0) {
490                                 Report.Error (591, Location, "Invalid value for argument to `System.AttributeUsage' attribute");
491                                 return null;
492                         }
493
494                         if (Type == TypeManager.indexer_name_type || Type == TypeManager.conditional_attribute_type) {
495                                 string v = pos_values [0] as string;
496                                 if (!Tokenizer.IsValidIdentifier (v) || Tokenizer.IsKeyword (v)) {
497                                         Report.Error (633, ((Argument)PosArguments[0]).Expr.Location,
498                                                 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
499                                         return null;
500                                 }
501                         }
502
503                         if (Type == TypeManager.methodimpl_attr_type && pos_values.Length == 1 &&
504                                 pd.Types [0] == TypeManager.short_type &&
505                                 !System.Enum.IsDefined (typeof (MethodImplOptions), pos_values [0].ToString ())) {
506                                 Error_AttributeEmitError ("Incorrect argument value.");
507                                 return null;
508                         }
509
510                         return constructor;
511                 }
512
513                 protected virtual bool ResolveNamedArguments (EmitContext ec)
514                 {
515                         int named_arg_count = NamedArguments.Count;
516
517                         ArrayList field_infos = new ArrayList (named_arg_count);
518                         ArrayList prop_infos  = new ArrayList (named_arg_count);
519                         ArrayList field_values = new ArrayList (named_arg_count);
520                         ArrayList prop_values = new ArrayList (named_arg_count);
521
522                         ArrayList seen_names = new ArrayList(named_arg_count);
523                         
524                         foreach (DictionaryEntry de in NamedArguments) {
525                                 string member_name = (string) de.Key;
526
527                                 if (seen_names.Contains(member_name)) {
528                                         Report.Error(643, Location, "'{0}' duplicate named attribute argument", member_name);
529                                         return false;
530                                 }                               
531                                 seen_names.Add(member_name);
532
533                                 Argument a = (Argument) de.Value;
534                                 if (!a.Resolve (ec, Location))
535                                         return false;
536
537                                 Expression member = Expression.MemberLookup (
538                                         ec.ContainerType, Type, member_name,
539                                         MemberTypes.Field | MemberTypes.Property,
540                                         BindingFlags.Public | BindingFlags.Instance,
541                                         Location);
542
543                                 if (member == null) {
544                                         member = Expression.MemberLookup (ec.ContainerType, Type, member_name,
545                                                 MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance,
546                                                 Location);
547
548                                         if (member != null) {
549                                                 Report.SymbolRelatedToPreviousError (member.Type);
550                                                 Expression.ErrorIsInaccesible (Location, member.GetSignatureForError ());
551                                                 return false;
552                                         }
553                                 }
554
555                                 if (member == null){
556                                         Expression.Error_TypeDoesNotContainDefinition (Location, Type, member_name);
557                                         return false;
558                                 }
559                                 
560                                 if (!(member is PropertyExpr || member is FieldExpr)) {
561                                         Error_InvalidNamedArgument (member_name);
562                                         return false;
563                                 }
564
565                                 if (a.Expr is TypeParameterExpr){
566                                         Error_TypeParameterInAttribute (Location);
567                                         return false;
568                                 }
569
570                                 ObsoleteAttribute obsolete_attr;
571
572                                 if (member is PropertyExpr) {
573                                         PropertyInfo pi = ((PropertyExpr) member).PropertyInfo;
574
575                                         if (!pi.CanWrite || !pi.CanRead) {
576                                                 Report.SymbolRelatedToPreviousError (pi);
577                                                 Error_InvalidNamedArgument (member_name);
578                                                 return false;
579                                         }
580
581                                         if (!IsValidArgumentType (member.Type)) {
582                                                 Report.SymbolRelatedToPreviousError (pi);
583                                                 Error_InvalidNamedAgrumentType (member_name);
584                                                 return false;
585                                         }
586
587                                         object value;
588                                         if (!a.Expr.GetAttributableValue (ec, member.Type, out value))
589                                                 return false;
590
591                                         PropertyBase pb = TypeManager.GetProperty (pi);
592                                         if (pb != null)
593                                                 obsolete_attr = pb.GetObsoleteAttribute ();
594                                         else
595                                                 obsolete_attr = AttributeTester.GetMemberObsoleteAttribute (pi);
596
597                                         prop_values.Add (value);
598                                         prop_infos.Add (pi);
599                                         
600                                 } else {
601                                         FieldInfo fi = ((FieldExpr) member).FieldInfo;
602
603                                         if (fi.IsInitOnly) {
604                                                 Error_InvalidNamedArgument (member_name);
605                                                 return false;
606                                         }
607
608                                         if (!IsValidArgumentType (member.Type)) {
609                                                 Report.SymbolRelatedToPreviousError (fi);
610                                                 Error_InvalidNamedAgrumentType (member_name);
611                                                 return false;
612                                         }
613
614                                         object value;
615                                         if (!a.Expr.GetAttributableValue (ec, member.Type, out value))
616                                                 return false;
617
618                                         FieldBase fb = TypeManager.GetField (fi);
619                                         if (fb != null)
620                                                 obsolete_attr = fb.GetObsoleteAttribute ();
621                                         else
622                                                 obsolete_attr = AttributeTester.GetMemberObsoleteAttribute (fi);
623
624                                         field_values.Add (value);                                       
625                                         field_infos.Add (fi);
626                                 }
627
628                                 if (obsolete_attr != null && !Owner.ResolveContext.IsInObsoleteScope)
629                                         AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location);
630                         }
631
632                         prop_info_arr = new PropertyInfo [prop_infos.Count];
633                         field_info_arr = new FieldInfo [field_infos.Count];
634                         field_values_arr = new object [field_values.Count];
635                         prop_values_arr = new object [prop_values.Count];
636
637                         field_infos.CopyTo  (field_info_arr, 0);
638                         field_values.CopyTo (field_values_arr, 0);
639
640                         prop_values.CopyTo  (prop_values_arr, 0);
641                         prop_infos.CopyTo   (prop_info_arr, 0);
642
643                         return true;
644                 }
645
646                 /// <summary>
647                 ///   Get a string containing a list of valid targets for the attribute 'attr'
648                 /// </summary>
649                 public string GetValidTargets ()
650                 {
651                         StringBuilder sb = new StringBuilder ();
652                         AttributeTargets targets = GetAttributeUsage (Type).ValidOn;
653
654                         if ((targets & AttributeTargets.Assembly) != 0)
655                                 sb.Append ("assembly, ");
656
657                         if ((targets & AttributeTargets.Module) != 0)
658                                 sb.Append ("module, ");
659
660                         if ((targets & AttributeTargets.Class) != 0)
661                                 sb.Append ("class, ");
662
663                         if ((targets & AttributeTargets.Struct) != 0)
664                                 sb.Append ("struct, ");
665
666                         if ((targets & AttributeTargets.Enum) != 0)
667                                 sb.Append ("enum, ");
668
669                         if ((targets & AttributeTargets.Constructor) != 0)
670                                 sb.Append ("constructor, ");
671
672                         if ((targets & AttributeTargets.Method) != 0)
673                                 sb.Append ("method, ");
674
675                         if ((targets & AttributeTargets.Property) != 0)
676                                 sb.Append ("property, indexer, ");
677
678                         if ((targets & AttributeTargets.Field) != 0)
679                                 sb.Append ("field, ");
680
681                         if ((targets & AttributeTargets.Event) != 0)
682                                 sb.Append ("event, ");
683
684                         if ((targets & AttributeTargets.Interface) != 0)
685                                 sb.Append ("interface, ");
686
687                         if ((targets & AttributeTargets.Parameter) != 0)
688                                 sb.Append ("parameter, ");
689
690                         if ((targets & AttributeTargets.Delegate) != 0)
691                                 sb.Append ("delegate, ");
692
693                         if ((targets & AttributeTargets.ReturnValue) != 0)
694                                 sb.Append ("return, ");
695
696 #if NET_2_0
697                         if ((targets & AttributeTargets.GenericParameter) != 0)
698                                 sb.Append ("type parameter, ");
699 #endif                  
700                         return sb.Remove (sb.Length - 2, 2).ToString ();
701                 }
702
703                 /// <summary>
704                 /// Returns AttributeUsage attribute based on types hierarchy
705                 /// </summary>
706                 static AttributeUsageAttribute GetAttributeUsage (Type type)
707                 {
708                         AttributeUsageAttribute ua = usage_attr_cache [type] as AttributeUsageAttribute;
709                         if (ua != null)
710                                 return ua;
711
712                         Class attr_class = TypeManager.LookupClass (type);
713
714                         if (attr_class == null) {
715                                 object[] usage_attr = type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
716                                 ua = (AttributeUsageAttribute)usage_attr [0];
717                                 usage_attr_cache.Add (type, ua);
718                                 return ua;
719                         }
720
721                         Attribute a = null;
722                         if (attr_class.OptAttributes != null)
723                                 a = attr_class.OptAttributes.Search (TypeManager.attribute_usage_type);
724
725                         if (a == null) {
726                                 if (attr_class.TypeBuilder.BaseType != TypeManager.attribute_type)
727                                         ua = GetAttributeUsage (attr_class.TypeBuilder.BaseType);
728                                 else
729                                         ua = DefaultUsageAttribute;
730                         } else {
731                                 ua = a.GetAttributeUsageAttribute ();
732                         }
733
734                         usage_attr_cache.Add (type, ua);
735                         return ua;
736                 }
737
738                 AttributeUsageAttribute GetAttributeUsageAttribute ()
739                 {
740                         if (pos_values == null)
741                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
742                                 // But because a lot of attribute class code must be rewritten will be better to wait...
743                                 Resolve ();
744
745                         if (resolve_error)
746                                 return DefaultUsageAttribute;
747
748                         AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)pos_values [0]);
749
750                         object field = GetPropertyValue ("AllowMultiple");
751                         if (field != null)
752                                 usage_attribute.AllowMultiple = (bool)field;
753
754                         field = GetPropertyValue ("Inherited");
755                         if (field != null)
756                                 usage_attribute.Inherited = (bool)field;
757
758                         return usage_attribute;
759                 }
760
761                 /// <summary>
762                 /// Returns custom name of indexer
763                 /// </summary>
764                 public string GetIndexerAttributeValue ()
765                 {
766                         if (pos_values == null)
767                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
768                                 // But because a lot of attribute class code must be rewritten will be better to wait...
769                                 Resolve ();
770
771                         if (resolve_error)
772                                 return null;
773
774                         return pos_values [0] as string;
775                 }
776
777                 /// <summary>
778                 /// Returns condition of ConditionalAttribute
779                 /// </summary>
780                 public string GetConditionalAttributeValue ()
781                 {
782                         if (pos_values == null)
783                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
784                                 // But because a lot of attribute class code must be rewritten will be better to wait...
785                                 Resolve ();
786
787                         if (resolve_error)
788                                 return null;
789
790                         return (string)pos_values [0];
791                 }
792
793                 /// <summary>
794                 /// Creates the instance of ObsoleteAttribute from this attribute instance
795                 /// </summary>
796                 public ObsoleteAttribute GetObsoleteAttribute ()
797                 {
798                         if (pos_values == null)
799                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
800                                 // But because a lot of attribute class code must be rewritten will be better to wait...
801                                 Resolve ();
802
803                         if (resolve_error)
804                                 return null;
805
806                         if (pos_values == null || pos_values.Length == 0)
807                                 return new ObsoleteAttribute ();
808
809                         if (pos_values.Length == 1)
810                                 return new ObsoleteAttribute ((string)pos_values [0]);
811
812                         return new ObsoleteAttribute ((string)pos_values [0], (bool)pos_values [1]);
813                 }
814
815                 /// <summary>
816                 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
817                 /// before ApplyAttribute. We need to resolve the arguments.
818                 /// This situation occurs when class deps is differs from Emit order.  
819                 /// </summary>
820                 public bool GetClsCompliantAttributeValue ()
821                 {
822                         if (pos_values == null)
823                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
824                                 // But because a lot of attribute class code must be rewritten will be better to wait...
825                                 Resolve ();
826
827                         if (resolve_error)
828                                 return false;
829
830                         return (bool)pos_values [0];
831                 }
832
833                 public Type GetCoClassAttributeValue ()
834                 {
835                         if (pos_values == null)
836                                 Resolve ();
837
838                         if (resolve_error)
839                                 return null;
840
841                         return (Type)pos_values [0];
842                 }
843
844                 public bool CheckTarget ()
845                 {
846                         string[] valid_targets = Owner.ValidAttributeTargets;
847                         if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
848                                 Target = Owner.AttributeTargets;
849                                 return true;
850                         }
851
852                         // TODO: we can skip the first item
853                         if (((IList) valid_targets).Contains (ExplicitTarget)) {
854                                 switch (ExplicitTarget) {
855                                 case "return": Target = AttributeTargets.ReturnValue; return true;
856                                 case "param": Target = AttributeTargets.Parameter; return true;
857                                 case "field": Target = AttributeTargets.Field; return true;
858                                 case "method": Target = AttributeTargets.Method; return true;
859                                 case "property": Target = AttributeTargets.Property; return true;
860                                 }
861                                 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
862                         }
863                                 
864                         StringBuilder sb = new StringBuilder ();
865                         foreach (string s in valid_targets) {
866                                 sb.Append (s);
867                                 sb.Append (", ");
868                         }
869                         sb.Remove (sb.Length - 2, 2);
870                         Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
871                                 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
872                         return false;
873                 }
874
875                 /// <summary>
876                 /// Tests permitted SecurityAction for assembly or other types
877                 /// </summary>
878                 protected virtual bool IsSecurityActionValid (bool for_assembly)
879                 {
880                         SecurityAction action = GetSecurityActionValue ();
881
882                         switch (action) {
883                         case SecurityAction.Demand:
884                         case SecurityAction.Assert:
885                         case SecurityAction.Deny:
886                         case SecurityAction.PermitOnly:
887                         case SecurityAction.LinkDemand:
888                         case SecurityAction.InheritanceDemand:
889                                 if (!for_assembly)
890                                         return true;
891                                 break;
892
893                         case SecurityAction.RequestMinimum:
894                         case SecurityAction.RequestOptional:
895                         case SecurityAction.RequestRefuse:
896                                 if (for_assembly)
897                                         return true;
898                                 break;
899
900                         default:
901                                 Error_AttributeEmitError ("SecurityAction is out of range");
902                                 return false;
903                         }
904
905                         Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
906                         return false;
907                 }
908
909                 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
910                 {
911                         return (SecurityAction)pos_values [0];
912                 }
913
914                 /// <summary>
915                 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
916                 /// </summary>
917                 /// <returns></returns>
918                 public void ExtractSecurityPermissionSet (ListDictionary permissions)
919                 {
920                         Type orig_assembly_type = null;
921
922                         if (TypeManager.LookupDeclSpace (Type) != null) {
923                                 if (!RootContext.StdLib) {
924                                         orig_assembly_type = Type.GetType (Type.FullName);
925                                 } else {
926                                         string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
927                                         if (orig_version_path == null) {
928                                                 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
929                                                 return;
930                                         }
931
932                                         if (orig_sec_assembly == null) {
933                                                 string file = Path.Combine (orig_version_path, Driver.OutputFile);
934                                                 orig_sec_assembly = Assembly.LoadFile (file);
935                                         }
936
937                                         orig_assembly_type = orig_sec_assembly.GetType (Type.FullName, true);
938                                         if (orig_assembly_type == null) {
939                                                 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' " +
940                                                                 "was not found in previous version of assembly");
941                                                 return;
942                                         }
943                                 }
944                         }
945
946                         SecurityAttribute sa;
947                         // For all non-selfreferencing security attributes we can avoid all hacks
948                         if (orig_assembly_type == null) {
949                                 sa = (SecurityAttribute) Activator.CreateInstance (Type, pos_values);
950
951                                 if (prop_info_arr != null) {
952                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
953                                                 PropertyInfo pi = prop_info_arr [i];
954                                                 pi.SetValue (sa, prop_values_arr [i], null);
955                                         }
956                                 }
957                         } else {
958                                 // HACK: All security attributes have same ctor syntax
959                                 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, new object[] { GetSecurityActionValue () } );
960
961                                 // All types are from newly created assembly but for invocation with old one we need to convert them
962                                 if (prop_info_arr != null) {
963                                         for (int i = 0; i < prop_info_arr.Length; ++i) {
964                                                 PropertyInfo emited_pi = prop_info_arr [i];
965                                                 // FIXME: We are missing return type filter
966                                                 // TODO: pi can be null
967                                                 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name);
968
969                                                 object old_instance = pi.PropertyType.IsEnum ?
970                                                         System.Enum.ToObject (pi.PropertyType, prop_values_arr [i]) :
971                                                         prop_values_arr [i];
972
973                                                 pi.SetValue (sa, old_instance, null);
974                                         }
975                                 }
976                         }
977
978                         IPermission perm;
979                         perm = sa.CreatePermission ();
980                         SecurityAction action = GetSecurityActionValue ();
981
982                         // IS is correct because for corlib we are using an instance from old corlib
983                         if (!(perm is System.Security.CodeAccessPermission)) {
984                                 switch (action) {
985                                 case SecurityAction.Demand:
986                                         action = (SecurityAction)13;
987                                         break;
988                                 case SecurityAction.LinkDemand:
989                                         action = (SecurityAction)14;
990                                         break;
991                                 case SecurityAction.InheritanceDemand:
992                                         action = (SecurityAction)15;
993                                         break;
994                                 }
995                         }
996
997                         PermissionSet ps = (PermissionSet)permissions [action];
998                         if (ps == null) {
999                                 if (sa is PermissionSetAttribute)
1000                                         ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
1001                                 else
1002                                         ps = new PermissionSet (PermissionState.None);
1003
1004                                 permissions.Add (action, ps);
1005                         } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
1006                                 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
1007                                 permissions [action] = ps;
1008                         }
1009                         ps.AddPermission (perm);
1010                 }
1011
1012                 public object GetPropertyValue (string name)
1013                 {
1014                         if (prop_info_arr == null)
1015                                 return null;
1016
1017                         for (int i = 0; i < prop_info_arr.Length; ++i) {
1018                                 if (prop_info_arr [i].Name == name)
1019                                         return prop_values_arr [i];
1020                         }
1021
1022                         return null;
1023                 }
1024
1025                 //
1026                 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1027                 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1028                 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1029                 //
1030 #if !NET_2_0
1031                 public UnmanagedMarshal GetMarshal (Attributable attr)
1032                 {
1033                         UnmanagedType UnmanagedType;
1034                         if (!RootContext.StdLib || pos_values [0].GetType () != typeof (UnmanagedType))
1035                                 UnmanagedType = (UnmanagedType) System.Enum.ToObject (typeof (UnmanagedType), pos_values [0]);
1036                         else
1037                                 UnmanagedType = (UnmanagedType) pos_values [0];
1038
1039                         object value = GetFieldValue ("SizeParamIndex");
1040                         if (value != null && UnmanagedType != UnmanagedType.LPArray) {
1041                                 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1042                                 return null;
1043                         }
1044
1045                         object o = GetFieldValue ("ArraySubType");
1046                         UnmanagedType array_sub_type = o == null ? (UnmanagedType) 0x50 /* NATIVE_MAX */ : (UnmanagedType) o;
1047
1048                         switch (UnmanagedType) {
1049                         case UnmanagedType.CustomMarshaler: {
1050                                 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
1051                                         BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1052                                 if (define_custom == null) {
1053                                         Report.RuntimeMissingSupport (Location, "set marshal info");
1054                                         return null;
1055                                 }
1056                                 
1057                                 object [] args = new object [4];
1058                                 args [0] = GetFieldValue ("MarshalTypeRef");
1059                                 args [1] = GetFieldValue ("MarshalCookie");
1060                                 args [2] = GetFieldValue ("MarshalType");
1061                                 args [3] = Guid.Empty;
1062                                 return (UnmanagedMarshal) define_custom.Invoke (null, args);
1063                         }
1064                         case UnmanagedType.LPArray: {
1065                                 object size_const = GetFieldValue ("SizeConst");
1066                                 object size_param_index = GetFieldValue ("SizeParamIndex");
1067
1068                                 if ((size_const != null) || (size_param_index != null)) {
1069                                         MethodInfo define_array = typeof (UnmanagedMarshal).GetMethod ("DefineLPArrayInternal",
1070                                                 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1071                                         if (define_array == null) {
1072                                                 Report.RuntimeMissingSupport (Location, "set marshal info");
1073                                                 return null;
1074                                         }
1075                                 
1076                                         object [] args = new object [3];
1077                                         args [0] = array_sub_type;
1078                                         args [1] = size_const == null ? -1 : size_const;
1079                                         args [2] = size_param_index == null ? -1 : size_param_index;
1080                                         return (UnmanagedMarshal) define_array.Invoke (null, args);
1081                                 }
1082                                 else
1083                                         return UnmanagedMarshal.DefineLPArray (array_sub_type);
1084                         }
1085                         case UnmanagedType.SafeArray:
1086                                 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
1087
1088                         case UnmanagedType.ByValArray:
1089                                 FieldBase fm = attr as FieldBase;
1090                                 if (fm == null) {
1091                                         Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1092                                         return null;
1093                                 }
1094                                 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1095
1096                         case UnmanagedType.ByValTStr:
1097                                 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1098
1099                         default:
1100                                 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
1101                         }
1102                 }
1103
1104                 object GetFieldValue (string name)
1105                 {
1106                         int i;
1107                         if (field_info_arr == null)
1108                                 return null;
1109                         i = 0;
1110                         foreach (FieldInfo fi in field_info_arr) {
1111                                 if (fi.Name == name)
1112                                         return GetValue (field_values_arr [i]);
1113                                 i++;
1114                         }
1115                         return null;
1116                 }
1117
1118                 static object GetValue (object value)
1119                 {
1120                         if (value is EnumConstant)
1121                                 return ((EnumConstant) value).GetValue ();
1122                         else
1123                                 return value;                           
1124                 }
1125                 
1126 #endif
1127
1128                 public CharSet GetCharSetValue ()
1129                 {
1130                         return (CharSet)System.Enum.Parse (typeof (CharSet), pos_values [0].ToString ());
1131                 }
1132
1133                 public bool HasField (string fieldName)
1134                 {
1135                         if (field_info_arr == null)
1136                                 return false;
1137
1138                         foreach (FieldInfo fi in field_info_arr) {
1139                                 if (fi.Name == fieldName)
1140                                         return true;
1141                         }
1142
1143                         return false;
1144                 }
1145
1146                 public bool IsInternalMethodImplAttribute {
1147                         get {
1148                                 if (Type != TypeManager.methodimpl_attr_type)
1149                                         return false;
1150
1151                                 MethodImplOptions options;
1152                                 if (pos_values[0].GetType () != typeof (MethodImplOptions))
1153                                         options = (MethodImplOptions)System.Enum.ToObject (typeof (MethodImplOptions), pos_values[0]);
1154                                 else
1155                                         options = (MethodImplOptions)pos_values[0];
1156
1157                                 return (options & MethodImplOptions.InternalCall) != 0;
1158                         }
1159                 }
1160
1161                 public LayoutKind GetLayoutKindValue ()
1162                 {
1163                         if (!RootContext.StdLib || pos_values [0].GetType () != typeof (LayoutKind))
1164                                 return (LayoutKind)System.Enum.ToObject (typeof (LayoutKind), pos_values [0]);
1165
1166                         return (LayoutKind)pos_values [0];
1167                 }
1168
1169                 public object GetParameterDefaultValue ()
1170                 {
1171                         return pos_values [0];
1172                 }
1173
1174                 public override bool Equals (object obj)
1175                 {
1176                         Attribute a = obj as Attribute;
1177                         if (a == null)
1178                                 return false;
1179
1180                         return Type == a.Type && Target == a.Target;
1181                 }
1182
1183                 public override int GetHashCode ()
1184                 {
1185                         return base.GetHashCode ();
1186                 }
1187
1188                 /// <summary>
1189                 /// Emit attribute for Attributable symbol
1190                 /// </summary>
1191                 public void Emit (ListDictionary allEmitted)
1192                 {
1193                         CustomAttributeBuilder cb = Resolve ();
1194                         if (cb == null)
1195                                 return;
1196
1197                         AttributeUsageAttribute usage_attr = GetAttributeUsage (Type);
1198                         if ((usage_attr.ValidOn & Target) == 0) {
1199                                 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
1200                                               "It is valid on `{1}' declarations only",
1201                                         GetSignatureForError (), GetValidTargets ());
1202                                 return;
1203                         }
1204
1205                         try {
1206                                 foreach (Attributable owner in owners)
1207                                         owner.ApplyAttributeBuilder (this, cb);
1208                         }
1209                         catch (Exception e) {
1210                                 Error_AttributeEmitError (e.Message);
1211                                 return;
1212                         }
1213
1214                         if (!usage_attr.AllowMultiple && allEmitted != null) {
1215                                 if (allEmitted.Contains (this)) {
1216                                         ArrayList a = allEmitted [this] as ArrayList;
1217                                         if (a == null) {
1218                                                 a = new ArrayList (2);
1219                                                 allEmitted [this] = a;
1220                                         }
1221                                         a.Add (this);
1222                                 } else {
1223                                         allEmitted.Add (this, null);
1224                                 }
1225                         }
1226
1227                         if (!RootContext.VerifyClsCompliance)
1228                                 return;
1229
1230                         // Here we are testing attribute arguments for array usage (error 3016)
1231                         if (Owner.IsClsComplianceRequired ()) {
1232                                 if (PosArguments != null) {
1233                                         foreach (Argument arg in PosArguments) { 
1234                                                 // Type is undefined (was error 246)
1235                                                 if (arg.Type == null)
1236                                                         return;
1237
1238                                                 if (arg.Type.IsArray) {
1239                                                         Report.Warning (3016, 1, Location, "Arrays as attribute arguments are not CLS-compliant");
1240                                                         return;
1241                                                 }
1242                                         }
1243                                 }
1244                         
1245                                 if (NamedArguments == null)
1246                                         return;
1247                         
1248                                 foreach (DictionaryEntry de in NamedArguments) {
1249                                         Argument arg  = (Argument) de.Value;
1250
1251                                         // Type is undefined (was error 246)
1252                                         if (arg.Type == null)
1253                                                 return;
1254
1255                                         if (arg.Type.IsArray) {
1256                                                 Report.Warning (3016, 1, Location, "Arrays as attribute arguments are not CLS-compliant");
1257                                                 return;
1258                                         }
1259                                 }
1260                         }
1261                 }
1262
1263                 private Expression GetValue () 
1264                 {
1265                         if (PosArguments == null || PosArguments.Count < 1)
1266                                 return null;
1267
1268                         return ((Argument) PosArguments [0]).Expr;
1269                 }
1270
1271                 public string GetString () 
1272                 {
1273                         Expression e = GetValue ();
1274                         if (e is StringConstant)
1275                                 return ((StringConstant)e).Value;
1276                         return null;
1277                 }
1278
1279                 public bool GetBoolean () 
1280                 {
1281                         Expression e = GetValue ();
1282                         if (e is BoolConstant)
1283                                 return ((BoolConstant)e).Value;
1284                         return false;
1285                 }
1286
1287                 public Type GetArgumentType ()
1288                 {
1289                         TypeOf e = GetValue () as TypeOf;
1290                         if (e == null)
1291                                 return null;
1292                         return e.TypeArgument;
1293                 }
1294
1295                 public override Expression CreateExpressionTree (EmitContext ec)
1296                 {
1297                         throw new NotSupportedException ("ET");
1298                 }
1299
1300                 public override Expression DoResolve (EmitContext ec)
1301                 {
1302                         throw new NotImplementedException ();
1303                 }
1304
1305                 public override void Emit (EmitContext ec)
1306                 {
1307                         throw new NotImplementedException ();
1308                 }
1309         }
1310         
1311
1312         /// <summary>
1313         /// For global attributes (assembly, module) we need special handling.
1314         /// Attributes can be located in the several files
1315         /// </summary>
1316         public class GlobalAttribute : Attribute
1317         {
1318                 public readonly NamespaceEntry ns;
1319
1320                 public GlobalAttribute (NamespaceEntry ns, string target, 
1321                                         Expression left_expr, string identifier, object[] args, Location loc, bool nameEscaped):
1322                         base (target, left_expr, identifier, args, loc, nameEscaped)
1323                 {
1324                         this.ns = ns;
1325                         this.owners = new Attributable[1];
1326                 }
1327                 
1328                 public override void AttachTo (Attributable owner)
1329                 {
1330                         if (ExplicitTarget == "assembly") {
1331                                 owners [0] = CodeGen.Assembly;
1332                                 return;
1333                         }
1334                         if (ExplicitTarget == "module") {
1335                                 owners [0] = CodeGen.Module;
1336                                 return;
1337                         }
1338                         throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget);
1339                 }
1340
1341                 void Enter ()
1342                 {
1343                         // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1344                         // each time a new file is parsed.  However, we need to use the NamespaceEntry
1345                         // in effect where the attribute was used.  Since code elsewhere cannot assume
1346                         // that the NamespaceEntry is right, just overwrite it.
1347                         //
1348                         // Precondition: RootContext.ToplevelTypes == null
1349
1350                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1351                                 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1352
1353                         RootContext.ToplevelTypes.NamespaceEntry = ns;
1354                 }
1355
1356                 protected override bool IsSecurityActionValid (bool for_assembly)
1357                 {
1358                         return base.IsSecurityActionValid (true);
1359                 }
1360
1361                 void Leave ()
1362                 {
1363                         RootContext.ToplevelTypes.NamespaceEntry = null;
1364                 }
1365
1366                 protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent)
1367                 {
1368                         try {
1369                                 Enter ();
1370                                 return base.ResolveAsTypeTerminal (expr, ec, silent);
1371                         }
1372                         finally {
1373                                 Leave ();
1374                         }
1375                 }
1376
1377                 protected override ConstructorInfo ResolveConstructor (EmitContext ec)
1378                 {
1379                         try {
1380                                 Enter ();
1381                                 return base.ResolveConstructor (ec);
1382                         }
1383                         finally {
1384                                 Leave ();
1385                         }
1386                 }
1387
1388                 protected override bool ResolveNamedArguments (EmitContext ec)
1389                 {
1390                         try {
1391                                 Enter ();
1392                                 return base.ResolveNamedArguments (ec);
1393                         }
1394                         finally {
1395                                 Leave ();
1396                         }
1397                 }
1398         }
1399
1400         public class Attributes {
1401                 public readonly ArrayList Attrs;
1402
1403                 public Attributes (Attribute a)
1404                 {
1405                         Attrs = new ArrayList ();
1406                         Attrs.Add (a);
1407                 }
1408
1409                 public Attributes (ArrayList attrs)
1410                 {
1411                         Attrs = attrs;
1412                 }
1413
1414                 public void AddAttributes (ArrayList attrs)
1415                 {
1416                         Attrs.AddRange (attrs);
1417                 }
1418
1419                 public void AttachTo (Attributable attributable)
1420                 {
1421                         foreach (Attribute a in Attrs)
1422                                 a.AttachTo (attributable);
1423                 }
1424
1425                 public Attributes Clone ()
1426                 {
1427                         ArrayList al = new ArrayList (Attrs.Count);
1428                         foreach (Attribute a in Attrs)
1429                                 al.Add (a.Clone ());
1430
1431                         return new Attributes (al);
1432                 }
1433
1434                 /// <summary>
1435                 /// Checks whether attribute target is valid for the current element
1436                 /// </summary>
1437                 public bool CheckTargets ()
1438                 {
1439                         foreach (Attribute a in Attrs) {
1440                                 if (!a.CheckTarget ())
1441                                         return false;
1442                         }
1443                         return true;
1444                 }
1445
1446                 public Attribute Search (Type t)
1447                 {
1448                         foreach (Attribute a in Attrs) {
1449                                 if (a.ResolveType () == t)
1450                                         return a;
1451                         }
1452                         return null;
1453                 }
1454
1455                 /// <summary>
1456                 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1457                 /// </summary>
1458                 public Attribute[] SearchMulti (Type t)
1459                 {
1460                         ArrayList ar = null;
1461
1462                         foreach (Attribute a in Attrs) {
1463                                 if (a.ResolveType () == t) {
1464                                         if (ar == null)
1465                                                 ar = new ArrayList ();
1466                                         ar.Add (a);
1467                                 }
1468                         }
1469
1470                         return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
1471                 }
1472
1473                 public void Emit ()
1474                 {
1475                         CheckTargets ();
1476
1477                         ListDictionary ld = Attrs.Count > 1 ? new ListDictionary () : null;
1478
1479                         foreach (Attribute a in Attrs)
1480                                 a.Emit (ld);
1481
1482                         if (ld == null || ld.Count == 0)
1483                                 return;
1484
1485                         foreach (DictionaryEntry d in ld) {
1486                                 if (d.Value == null)
1487                                         continue;
1488
1489                                 foreach (Attribute collision in (ArrayList)d.Value)
1490                                         Report.SymbolRelatedToPreviousError (collision.Location, "");
1491
1492                                 Attribute a = (Attribute)d.Key;
1493                                 Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
1494                                         a.GetSignatureForError ());
1495                         }
1496                 }
1497
1498                 public bool Contains (Type t)
1499                 {
1500                         return Search (t) != null;
1501                 }
1502         }
1503
1504         /// <summary>
1505         /// Helper class for attribute verification routine.
1506         /// </summary>
1507         sealed class AttributeTester
1508         {
1509                 static PtrHashtable analyzed_types;
1510                 static PtrHashtable analyzed_types_obsolete;
1511                 static PtrHashtable analyzed_member_obsolete;
1512                 static PtrHashtable analyzed_method_excluded;
1513                 static PtrHashtable fixed_buffer_cache;
1514
1515                 static object TRUE = new object ();
1516                 static object FALSE = new object ();
1517
1518                 static AttributeTester ()
1519                 {
1520                         Reset ();
1521                 }
1522
1523                 private AttributeTester ()
1524                 {
1525                 }
1526
1527                 public static void Reset ()
1528                 {
1529                         analyzed_types = new PtrHashtable ();
1530                         analyzed_types_obsolete = new PtrHashtable ();
1531                         analyzed_member_obsolete = new PtrHashtable ();
1532                         analyzed_method_excluded = new PtrHashtable ();
1533                         fixed_buffer_cache = new PtrHashtable ();
1534                 }
1535
1536                 public enum Result {
1537                         Ok,
1538                         RefOutArrayError,
1539                         ArrayArrayError
1540                 }
1541
1542                 /// <summary>
1543                 /// Returns true if parameters of two compared methods are CLS-Compliant.
1544                 /// It tests differing only in ref or out, or in array rank.
1545                 /// </summary>
1546                 public static Result AreOverloadedMethodParamsClsCompliant (AParametersCollection pa, AParametersCollection pb) 
1547                 {
1548                         Type [] types_a = pa.Types;
1549                         Type [] types_b = pb.Types;
1550                         if (types_a == null || types_b == null)
1551                                 return Result.Ok;
1552
1553                         if (types_a.Length != types_b.Length)
1554                                 return Result.Ok;
1555
1556                         Result result = Result.Ok;
1557                         for (int i = 0; i < types_b.Length; ++i) {
1558                                 Type aType = types_a [i];
1559                                 Type bType = types_b [i];
1560
1561                                 if (aType.IsArray && bType.IsArray) {
1562                                         Type a_el_type = aType.GetElementType ();
1563                                         Type b_el_type = bType.GetElementType ();
1564                                         if (aType.GetArrayRank () != bType.GetArrayRank () && a_el_type == b_el_type) {
1565                                                 result = Result.RefOutArrayError;
1566                                                 continue;
1567                                         }
1568
1569                                         if (a_el_type.IsArray || b_el_type.IsArray) {
1570                                                 result = Result.ArrayArrayError;
1571                                                 continue;
1572                                         }
1573                                 }
1574
1575                                 if (aType != bType)
1576                                         return Result.Ok;
1577
1578                                 if (pa.FixedParameters [i].ModFlags != pb.FixedParameters [i].ModFlags)
1579                                         result = Result.RefOutArrayError;
1580                         }
1581                         return result;
1582                 }
1583
1584                 /// <summary>
1585                 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1586                 /// </summary>
1587                 public static bool IsClsCompliant (Type type) 
1588                 {
1589                         if (type == null)
1590                                 return true;
1591
1592                         object type_compliance = analyzed_types[type];
1593                         if (type_compliance != null)
1594                                 return type_compliance == TRUE;
1595
1596                         if (type.IsPointer) {
1597                                 analyzed_types.Add (type, FALSE);
1598                                 return false;
1599                         }
1600
1601                         bool result;
1602                         if (type.IsArray) {
1603                                 result = IsClsCompliant (TypeManager.GetElementType (type));
1604                         } else if (TypeManager.IsNullableType (type)) {
1605                                 result = IsClsCompliant (TypeManager.GetTypeArguments (type) [0]);
1606                         } else {
1607                                 result = AnalyzeTypeCompliance (type);
1608                         }
1609                         analyzed_types.Add (type, result ? TRUE : FALSE);
1610                         return result;
1611                 }        
1612         
1613                 /// <summary>
1614                 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1615                 /// </summary>
1616                 public static IFixedBuffer GetFixedBuffer (FieldInfo fi)
1617                 {
1618                         // Fixed buffer helper type is generated as value type
1619                         if (!fi.FieldType.IsValueType)
1620                                 return null;
1621
1622                         FieldBase fb = TypeManager.GetField (fi);
1623                         if (fb != null) {
1624                                 return fb as IFixedBuffer;
1625                         }
1626                         
1627                         if (TypeManager.GetConstant (fi) != null)
1628                                 return null;
1629
1630                         object o = fixed_buffer_cache [fi];
1631                         if (o == null) {
1632                                 if (TypeManager.fixed_buffer_attr_type == null)
1633                                         return null;
1634
1635                                 if (!fi.IsDefined (TypeManager.fixed_buffer_attr_type, false)) {
1636                                         fixed_buffer_cache.Add (fi, FALSE);
1637                                         return null;
1638                                 }
1639                                 
1640                                 IFixedBuffer iff = new FixedFieldExternal (fi);
1641                                 fixed_buffer_cache.Add (fi, iff);
1642                                 return iff;
1643                         }
1644
1645                         if (o == FALSE)
1646                                 return null;
1647
1648                         return (IFixedBuffer)o;
1649                 }
1650
1651                 public static void VerifyModulesClsCompliance ()
1652                 {
1653                         Module[] modules = RootNamespace.Global.Modules;
1654                         if (modules == null)
1655                                 return;
1656
1657                         // The first module is generated assembly
1658                         for (int i = 1; i < modules.Length; ++i) {
1659                                 Module module = modules [i];
1660                                 if (!GetClsCompliantAttributeValue (module, null)) {
1661                                         Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1662                                                       "to match the assembly", module.Name);
1663                                         return;
1664                                 }
1665                         }
1666                 }
1667
1668                 public static Type GetImportedIgnoreCaseClsType (string name)
1669                 {
1670                         foreach (Assembly a in RootNamespace.Global.Assemblies) {
1671                                 Type t = a.GetType (name, false, true);
1672                                 if (t == null)
1673                                         continue;
1674
1675                                 if (IsClsCompliant (t))
1676                                         return t;
1677                         }
1678                         return null;
1679                 }
1680
1681                 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider, Assembly a) 
1682                 {
1683                         if (TypeManager.cls_compliant_attribute_type == null)
1684                                 return false;
1685
1686                         object[] cls_attr = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1687                         if (cls_attr.Length == 0) {
1688                                 if (a == null)
1689                                         return false;
1690
1691                                 return GetClsCompliantAttributeValue (a, null);
1692                         }
1693                         
1694                         return ((CLSCompliantAttribute)cls_attr [0]).IsCompliant;
1695                 }
1696
1697                 static bool AnalyzeTypeCompliance (Type type)
1698                 {
1699                         type = TypeManager.DropGenericTypeArguments (type);
1700                         DeclSpace ds = TypeManager.LookupDeclSpace (type);
1701                         if (ds != null) {
1702                                 return ds.IsClsComplianceRequired ();
1703                         }
1704
1705                         if (TypeManager.IsGenericParameter (type))
1706                                 return true;
1707
1708                         return GetClsCompliantAttributeValue (type, type.Assembly);
1709                 }
1710
1711                 /// <summary>
1712                 /// Returns instance of ObsoleteAttribute when type is obsolete
1713                 /// </summary>
1714                 public static ObsoleteAttribute GetObsoleteAttribute (Type type)
1715                 {
1716                         object type_obsolete = analyzed_types_obsolete [type];
1717                         if (type_obsolete == FALSE)
1718                                 return null;
1719
1720                         if (type_obsolete != null)
1721                                 return (ObsoleteAttribute)type_obsolete;
1722
1723                         ObsoleteAttribute result = null;
1724                         if (TypeManager.HasElementType (type)) {
1725                                 result = GetObsoleteAttribute (TypeManager.GetElementType (type));
1726                         } else if (TypeManager.IsGenericParameter (type) || TypeManager.IsGenericType (type))
1727                                 return null;
1728                         else {
1729                                 DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
1730
1731                                 // Type is external, we can get attribute directly
1732                                 if (type_ds == null) {
1733                                         if (TypeManager.obsolete_attribute_type != null) {
1734                                                 object [] attribute = type.GetCustomAttributes (TypeManager.obsolete_attribute_type, false);
1735                                                 if (attribute.Length == 1)
1736                                                         result = (ObsoleteAttribute) attribute [0];
1737                                         }
1738                                 } else {
1739                                         result = type_ds.GetObsoleteAttribute ();
1740                                 }
1741                         }
1742
1743                         // Cannot use .Add because of corlib bootstrap
1744                         analyzed_types_obsolete [type] = result == null ? FALSE : result;
1745                         return result;
1746                 }
1747
1748                 /// <summary>
1749                 /// Returns instance of ObsoleteAttribute when method is obsolete
1750                 /// </summary>
1751                 public static ObsoleteAttribute GetMethodObsoleteAttribute (MethodBase mb)
1752                 {
1753                         IMethodData mc = TypeManager.GetMethod (mb);
1754                         if (mc != null) 
1755                                 return mc.GetObsoleteAttribute ();
1756
1757                         // compiler generated methods are not registered by AddMethod
1758                         if (mb.DeclaringType is TypeBuilder)
1759                                 return null;
1760
1761                         MemberInfo mi = TypeManager.GetPropertyFromAccessor (mb);
1762                         if (mi != null)
1763                                 return GetMemberObsoleteAttribute (mi);
1764
1765                         mi = TypeManager.GetEventFromAccessor (mb);
1766                         if (mi != null)
1767                                 return GetMemberObsoleteAttribute (mi);
1768
1769                         return GetMemberObsoleteAttribute (mb);
1770                 }
1771
1772                 /// <summary>
1773                 /// Returns instance of ObsoleteAttribute when member is obsolete
1774                 /// </summary>
1775                 public static ObsoleteAttribute GetMemberObsoleteAttribute (MemberInfo mi)
1776                 {
1777                         object type_obsolete = analyzed_member_obsolete [mi];
1778                         if (type_obsolete == FALSE)
1779                                 return null;
1780
1781                         if (type_obsolete != null)
1782                                 return (ObsoleteAttribute)type_obsolete;
1783
1784                         if ((mi.DeclaringType is TypeBuilder) || TypeManager.IsGenericType (mi.DeclaringType))
1785                                 return null;
1786
1787                         if (TypeManager.obsolete_attribute_type == null)
1788                                 return null;
1789
1790                         ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false)
1791                                 as ObsoleteAttribute;
1792                         analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
1793                         return oa;
1794                 }
1795
1796                 /// <summary>
1797                 /// Common method for Obsolete error/warning reporting.
1798                 /// </summary>
1799                 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc)
1800                 {
1801                         if (oa.IsError) {
1802                                 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1803                                 return;
1804                         }
1805
1806                         if (oa.Message == null || oa.Message.Length == 0) {
1807                                 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1808                                 return;
1809                         }
1810                         Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1811                 }
1812
1813                 public static bool IsConditionalMethodExcluded (MethodBase mb, Location loc)
1814                 {
1815                         object excluded = analyzed_method_excluded [mb];
1816                         if (excluded != null)
1817                                 return excluded == TRUE ? true : false;
1818
1819                         if (TypeManager.conditional_attribute_type == null)
1820                                 return false;
1821
1822                         ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true)
1823                                 as ConditionalAttribute[];
1824                         if (attrs.Length == 0) {
1825                                 analyzed_method_excluded.Add (mb, FALSE);
1826                                 return false;
1827                         }
1828
1829                         foreach (ConditionalAttribute a in attrs) {
1830                                 if (loc.CompilationUnit.IsConditionalDefined (a.ConditionString)) {
1831                                         analyzed_method_excluded.Add (mb, FALSE);
1832                                         return false;
1833                                 }
1834                         }
1835
1836                         analyzed_method_excluded.Add (mb, TRUE);
1837                         return true;
1838                 }
1839
1840                 /// <summary>
1841                 /// Analyzes class whether it has attribute which has ConditionalAttribute
1842                 /// and its condition is not defined.
1843                 /// </summary>
1844                 public static bool IsAttributeExcluded (Type type, Location loc)
1845                 {
1846                         if (!type.IsClass)
1847                                 return false;
1848
1849                         Class class_decl = TypeManager.LookupDeclSpace (type) as Class;
1850
1851                         // TODO: add caching
1852                         // TODO: merge all Type bases attribute caching to one cache to save memory
1853                         if (class_decl == null && TypeManager.conditional_attribute_type != null) {
1854                                 object[] attributes = type.GetCustomAttributes (TypeManager.conditional_attribute_type, false);
1855                                 foreach (ConditionalAttribute ca in attributes) {
1856                                         if (loc.CompilationUnit.IsConditionalDefined (ca.ConditionString))
1857                                                 return false;
1858                                 }
1859                                 return attributes.Length > 0;
1860                         }
1861
1862                         return class_decl.IsExcluded ();
1863                 }
1864
1865                 public static Type GetCoClassAttribute (Type type)
1866                 {
1867                         TypeContainer tc = TypeManager.LookupInterface (type);
1868                         if (tc == null) {
1869                                 if (TypeManager.coclass_attr_type == null)
1870                                         return null;
1871
1872                                 object[] o = type.GetCustomAttributes (TypeManager.coclass_attr_type, false);
1873                                 if (o.Length < 1)
1874                                         return null;
1875                                 return ((System.Runtime.InteropServices.CoClassAttribute)o[0]).CoClass;
1876                         }
1877
1878                         if (tc.OptAttributes == null || TypeManager.coclass_attr_type == null)
1879                                 return null;
1880
1881                         Attribute a = tc.OptAttributes.Search (TypeManager.coclass_attr_type);
1882                         if (a == null)
1883                                 return null;
1884
1885                         return a.GetCoClassAttributeValue ();
1886                 }
1887         }
1888 }