Merge branch 'sgen-android'
[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.Collections.Generic;
15 using System.Runtime.InteropServices;
16 using System.Runtime.CompilerServices;
17 using System.Security; 
18 using System.Security.Permissions;
19 using System.Text;
20 using System.IO;
21
22 #if STATIC
23 using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
24 using IKVM.Reflection;
25 using IKVM.Reflection.Emit;
26 #else
27 using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
28 using System.Reflection;
29 using System.Reflection.Emit;
30 #endif
31
32 namespace Mono.CSharp {
33
34         /// <summary>
35         ///   Base class for objects that can have Attributes applied to them.
36         /// </summary>
37         public abstract class Attributable {
38                 //
39                 // Holds all attributes attached to this element
40                 //
41                 protected Attributes attributes;
42
43                 public void AddAttributes (Attributes attrs, IMemberContext context)
44                 {
45                         if (attrs == null)
46                                 return;
47
48                         if (attributes == null)
49                                 attributes = attrs;
50                         else
51                                 throw new NotImplementedException ();
52
53                         attributes.AttachTo (this, context);
54                 }
55
56                 public Attributes OptAttributes {
57                         get {
58                                 return attributes;
59                         }
60                         set {
61                                 attributes = value;
62                         }
63                 }
64
65                 /// <summary>
66                 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
67                 /// </summary>
68                 public abstract void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa);
69
70                 /// <summary>
71                 /// Returns one AttributeTarget for this element.
72                 /// </summary>
73                 public abstract AttributeTargets AttributeTargets { get; }
74
75                 public abstract bool IsClsComplianceRequired ();
76
77                 /// <summary>
78                 /// Gets list of valid attribute targets for explicit target declaration.
79                 /// The first array item is default target. Don't break this rule.
80                 /// </summary>
81                 public abstract string[] ValidAttributeTargets { get; }
82         };
83
84         public class Attribute : Expression
85         {
86                 public readonly string ExplicitTarget;
87                 public AttributeTargets Target;
88                 readonly ATypeNameExpression expression;
89
90                 Arguments PosArguments;
91                 Arguments NamedArguments;
92
93                 bool resolve_error;
94                 bool arg_resolved;
95                 readonly bool nameEscaped;
96
97                 //
98                 // An attribute can be attached to multiple targets (e.g. multiple fields)
99                 //
100                 protected Attributable[] targets;
101
102                 //
103                 // A member context for the attribute, it's much easier to hold it here
104                 // than trying to pull it during resolve
105                 //
106                 IMemberContext context;
107
108                 public static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
109                 static Assembly orig_sec_assembly;
110                 public static readonly object[] EmptyObject = new object [0];
111
112                 List<KeyValuePair<MemberExpr, NamedArgument>> named_values;
113
114                 // Cache for parameter-less attributes
115                 static Dictionary<TypeSpec, MethodSpec> att_cache;
116
117                 public Attribute (string target, ATypeNameExpression expr, Arguments[] args, Location loc, bool nameEscaped)
118                 {
119                         this.expression = expr;
120                         if (args != null) {
121                                 PosArguments = args [0];
122                                 NamedArguments = args [1];                              
123                         }
124                         this.loc = loc;
125                         ExplicitTarget = target;
126                         this.nameEscaped = nameEscaped;
127                 }
128
129                 void AddModuleCharSet (ResolveContext rc)
130                 {
131                         const string dll_import_char_set = "CharSet";
132
133                         //
134                         // Only when not customized by user
135                         //
136                         if (HasField (dll_import_char_set))
137                                 return;
138
139                         if (!rc.Module.PredefinedTypes.CharSet.IsDefined) {
140                                 return;
141                         }
142
143                         if (NamedArguments == null)
144                                 NamedArguments = new Arguments (1);
145
146                         var value = Constant.CreateConstant (rc, rc.Module.PredefinedTypes.CharSet.TypeSpec, rc.Module.DefaultCharSet, Location);
147                         NamedArguments.Add (new NamedArgument (dll_import_char_set, loc, value));
148                 }
149
150                 public Attribute Clone ()
151                 {
152                         Attribute a = new Attribute (ExplicitTarget, expression, null, loc, nameEscaped);
153                         a.PosArguments = PosArguments;
154                         a.NamedArguments = NamedArguments;
155                         return a;
156                 }
157
158                 static Attribute ()
159                 {
160                         Reset ();
161                 }
162
163                 public static void Reset ()
164                 {
165                         att_cache = new Dictionary<TypeSpec, MethodSpec> ();
166                 }
167
168                 //
169                 // When the same attribute is attached to multiple fiels
170                 // we use @target field as a list of targets. The attribute
171                 // has to be resolved only once but emitted for each target.
172                 //
173                 public void AttachTo (Attributable target, IMemberContext context)
174                 {
175                         if (this.targets == null) {
176                                 this.targets = new Attributable[] { target };
177                                 this.context = context;
178                                 return;
179                         }
180
181                         // Resize target array
182                         Attributable[] new_array = new Attributable [this.targets.Length + 1];
183                         targets.CopyTo (new_array, 0);
184                         new_array [targets.Length] = target;
185                         this.targets = new_array;
186
187                         // No need to update context, different targets cannot have
188                         // different contexts, it's enough to remove same attributes
189                         // from secondary members.
190
191                         target.OptAttributes = null;
192                 }
193
194                 static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name)
195                 {
196                         rc.Report.Error (617, name.Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
197                                       "must be fields which are not readonly, static, const or read-write properties which are " +
198                                       "public and not static",
199                               name.Name);
200                 }
201
202                 static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name)
203                 {
204                         rc.Report.Error (655, name.Location,
205                                 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
206                                 name.Name);
207                 }
208
209                 public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc)
210                 {
211                         context.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression");
212                 }
213                 
214                 public void Error_MissingGuidAttribute ()
215                 {
216                         Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
217                 }
218
219                 public void Error_MisusedExtensionAttribute ()
220                 {
221                         Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
222                 }
223
224                 public void Error_MisusedDynamicAttribute ()
225                 {
226                         Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
227                 }
228
229                 /// <summary>
230                 /// This is rather hack. We report many emit attribute error with same error to be compatible with
231                 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
232                 /// </summary>
233                 public void Error_AttributeEmitError (string inner)
234                 {
235                         Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
236                                       TypeManager.CSharpName (Type), inner);
237                 }
238
239                 public void Error_InvalidSecurityParent ()
240                 {
241                         Error_AttributeEmitError ("it is attached to invalid parent");
242                 }
243
244                 Attributable Owner {
245                         get {
246                                 return targets [0];
247                         }
248                 }
249
250                 protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
251                 {
252                         return expr.ResolveAsTypeTerminal (ec, false);
253                 }
254
255                 TypeSpec ResolvePossibleAttributeType (ATypeNameExpression expr, ref bool is_attr)
256                 {
257                         TypeExpr te = ResolveAsTypeTerminal (expr, context);
258                         if (te == null)
259                                 return null;
260
261                         TypeSpec t = te.Type;
262                         if (t.IsAttribute) {
263                                 is_attr = true;
264                         } else {
265                                 Report.SymbolRelatedToPreviousError (t);
266                                 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
267                         }
268                         return t;
269                 }
270
271                 /// <summary>
272                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
273                 /// </summary>
274                 void ResolveAttributeType ()
275                 {
276                         SessionReportPrinter resolve_printer = new SessionReportPrinter ();
277                         ReportPrinter prev_recorder = context.Compiler.Report.SetPrinter (resolve_printer);
278
279                         bool t1_is_attr = false;
280                         bool t2_is_attr = false;
281                         TypeSpec t1, t2;
282                         ATypeNameExpression expanded = null;
283
284                         try {
285                                 t1 = ResolvePossibleAttributeType (expression, ref t1_is_attr);
286
287                                 if (nameEscaped) {
288                                         t2 = null;
289                                 } else {
290                                         expanded = (ATypeNameExpression) expression.Clone (null);
291                                         expanded.Name += "Attribute";
292
293                                         t2 = ResolvePossibleAttributeType (expanded, ref t2_is_attr);
294                                 }
295
296                                 resolve_printer.EndSession ();
297                         } finally {
298                                 context.Compiler.Report.SetPrinter (prev_recorder);
299                         }
300
301                         if (t1_is_attr && t2_is_attr) {
302                                 Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
303                                         GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ());
304                                 resolve_error = true;
305                                 return;
306                         }
307
308                         if (t1_is_attr) {
309                                 Type = t1;
310                                 return;
311                         }
312
313                         if (t2_is_attr) {
314                                 Type = t2;
315                                 return;
316                         }
317
318                         resolve_printer.Merge (prev_recorder);
319                         resolve_error = true;
320                 }
321
322                 public virtual TypeSpec ResolveType ()
323                 {
324                         if (Type == null && !resolve_error)
325                                 ResolveAttributeType ();
326                         return Type;
327                 }
328
329                 public override string GetSignatureForError ()
330                 {
331                         if (Type != null)
332                                 return TypeManager.CSharpName (Type);
333
334                         return expression.GetSignatureForError ();
335                 }
336
337                 public bool HasSecurityAttribute {
338                         get {
339                                 PredefinedAttribute pa = context.Module.PredefinedAttributes.Security;
340                                 return pa.IsDefined && TypeSpec.IsBaseClass (type, pa.TypeSpec, false);
341                         }
342                 }
343
344                 public bool IsValidSecurityAttribute ()
345                 {
346                         return HasSecurityAttribute && IsSecurityActionValid (false);
347                 }
348
349                 static bool IsValidArgumentType (TypeSpec t)
350                 {
351                         if (t.IsArray)
352                                 t = TypeManager.GetElementType (t);
353
354                         return t == TypeManager.string_type ||
355                                 TypeManager.IsPrimitiveType (t) ||
356                                 TypeManager.IsEnumType (t) ||
357                                 t == TypeManager.object_type ||
358                                 t == TypeManager.type_type;
359                 }
360
361                 // TODO: Don't use this ambiguous value
362                 public string Name {
363                         get { return expression.Name; }
364                 }
365
366                 public Report Report {
367                         get { return context.Compiler.Report; }
368                 }
369
370                 public MethodSpec Resolve ()
371                 {
372                         if (resolve_error)
373                                 return null;
374
375                         resolve_error = true;
376                         arg_resolved = true;
377
378                         if (Type == null) {
379                                 ResolveAttributeType ();
380                                 if (Type == null)
381                                         return null;
382                         }
383
384                         if (Type.IsAbstract) {
385                                 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
386                                 return null;
387                         }
388
389                         ObsoleteAttribute obsolete_attr = Type.GetAttributeObsolete ();
390                         if (obsolete_attr != null) {
391                                 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location, Report);
392                         }
393
394                         MethodSpec ctor;
395                         // Try if the attribute is simple has been resolved before
396                         if (PosArguments == null && NamedArguments == null) {
397                                 if (att_cache.TryGetValue (Type, out ctor)) {
398                                         resolve_error = false;
399                                         return ctor;
400                                 }
401                         }
402
403                         ResolveContext rc = new ResolveContext (context, ResolveContext.Options.ConstantScope);
404                         ctor = ResolveConstructor (rc);
405                         if (ctor == null) {
406                                 return null;
407                         }
408
409                         //
410                         // Add [module: DefaultCharSet] to all DllImport import attributes
411                         //
412                         var module = context.Module;
413                         if (Type == module.PredefinedAttributes.DllImport && module.HasDefaultCharSet) {
414                                 AddModuleCharSet (rc);
415                         }
416
417                         if (NamedArguments != null && !ResolveNamedArguments (rc)) {
418                                 return null;
419                         }
420
421                         resolve_error = false;
422                         return ctor;
423                 }
424
425                 protected virtual MethodSpec ResolveConstructor (ResolveContext ec)
426                 {
427                         if (PosArguments != null) {
428                                 bool dynamic;
429                                 PosArguments.Resolve (ec, out dynamic);
430                                 if (dynamic) {
431                                         Error_AttributeArgumentIsDynamic (ec.MemberContext, loc);
432                                         return null;
433                                 }
434                         }
435
436                         return ConstructorLookup (ec, Type, ref PosArguments, loc);
437                 }
438
439                 protected virtual bool ResolveNamedArguments (ResolveContext ec)
440                 {
441                         int named_arg_count = NamedArguments.Count;
442                         var seen_names = new List<string> (named_arg_count);
443
444                         named_values = new List<KeyValuePair<MemberExpr, NamedArgument>> (named_arg_count);
445                         
446                         foreach (NamedArgument a in NamedArguments) {
447                                 string name = a.Name;
448                                 if (seen_names.Contains (name)) {
449                                         ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name);
450                                         continue;
451                                 }                       
452         
453                                 seen_names.Add (name);
454
455                                 a.Resolve (ec);
456
457                                 Expression member = Expression.MemberLookup (ec, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
458
459                                 if (member == null) {
460                                         member = Expression.MemberLookup (null, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
461
462                                         if (member != null) {
463                                                 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
464                                                 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
465                                                 return false;
466                                         }
467                                 }
468
469                                 if (member == null){
470                                         Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name);
471                                         return false;
472                                 }
473                                 
474                                 if (!(member is PropertyExpr || member is FieldExpr)) {
475                                         Error_InvalidNamedArgument (ec, a);
476                                         return false;
477                                 }
478
479                                 ObsoleteAttribute obsolete_attr;
480
481                                 if (member is PropertyExpr) {
482                                         var pi = ((PropertyExpr) member).PropertyInfo;
483
484                                         if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) {
485                                                 ec.Report.SymbolRelatedToPreviousError (pi);
486                                                 Error_InvalidNamedArgument (ec, a);
487                                                 return false;
488                                         }
489
490                                         if (!IsValidArgumentType (member.Type)) {
491                                                 ec.Report.SymbolRelatedToPreviousError (pi);
492                                                 Error_InvalidNamedArgumentType (ec, a);
493                                                 return false;
494                                         }
495
496                                         obsolete_attr = pi.GetAttributeObsolete ();
497                                         pi.MemberDefinition.SetIsAssigned ();
498                                 } else {
499                                         var fi = ((FieldExpr) member).Spec;
500
501                                         if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) {
502                                                 Error_InvalidNamedArgument (ec, a);
503                                                 return false;
504                                         }
505
506                                         if (!IsValidArgumentType (member.Type)) {
507                                                 ec.Report.SymbolRelatedToPreviousError (fi);
508                                                 Error_InvalidNamedArgumentType (ec, a);
509                                                 return false;
510                                         }
511
512                                         obsolete_attr = fi.GetAttributeObsolete ();
513                                         fi.MemberDefinition.SetIsAssigned ();
514                                 }
515
516                                 if (obsolete_attr != null && !context.IsObsolete)
517                                         AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location, Report);
518
519                                 if (a.Type != member.Type) {
520                                         a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location);
521                                 }
522
523                                 if (a.Expr != null)
524                                         named_values.Add (new KeyValuePair<MemberExpr, NamedArgument> ((MemberExpr) member, a));
525                         }
526
527                         return true;
528                 }
529
530                 /// <summary>
531                 ///   Get a string containing a list of valid targets for the attribute 'attr'
532                 /// </summary>
533                 public string GetValidTargets ()
534                 {
535                         StringBuilder sb = new StringBuilder ();
536                         AttributeTargets targets = Type.GetAttributeUsage (context.Module.PredefinedAttributes.AttributeUsage).ValidOn;
537
538                         if ((targets & AttributeTargets.Assembly) != 0)
539                                 sb.Append ("assembly, ");
540
541                         if ((targets & AttributeTargets.Module) != 0)
542                                 sb.Append ("module, ");
543
544                         if ((targets & AttributeTargets.Class) != 0)
545                                 sb.Append ("class, ");
546
547                         if ((targets & AttributeTargets.Struct) != 0)
548                                 sb.Append ("struct, ");
549
550                         if ((targets & AttributeTargets.Enum) != 0)
551                                 sb.Append ("enum, ");
552
553                         if ((targets & AttributeTargets.Constructor) != 0)
554                                 sb.Append ("constructor, ");
555
556                         if ((targets & AttributeTargets.Method) != 0)
557                                 sb.Append ("method, ");
558
559                         if ((targets & AttributeTargets.Property) != 0)
560                                 sb.Append ("property, indexer, ");
561
562                         if ((targets & AttributeTargets.Field) != 0)
563                                 sb.Append ("field, ");
564
565                         if ((targets & AttributeTargets.Event) != 0)
566                                 sb.Append ("event, ");
567
568                         if ((targets & AttributeTargets.Interface) != 0)
569                                 sb.Append ("interface, ");
570
571                         if ((targets & AttributeTargets.Parameter) != 0)
572                                 sb.Append ("parameter, ");
573
574                         if ((targets & AttributeTargets.Delegate) != 0)
575                                 sb.Append ("delegate, ");
576
577                         if ((targets & AttributeTargets.ReturnValue) != 0)
578                                 sb.Append ("return, ");
579
580                         if ((targets & AttributeTargets.GenericParameter) != 0)
581                                 sb.Append ("type parameter, ");
582
583                         return sb.Remove (sb.Length - 2, 2).ToString ();
584                 }
585
586                 public AttributeUsageAttribute GetAttributeUsageAttribute ()
587                 {
588                         if (!arg_resolved)
589                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
590                                 // But because a lot of attribute class code must be rewritten will be better to wait...
591                                 Resolve ();
592
593                         if (resolve_error)
594                                 return DefaultUsageAttribute;
595
596                         AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)((Constant) PosArguments [0].Expr).GetValue ());
597
598                         var field = GetNamedValue ("AllowMultiple") as BoolConstant;
599                         if (field != null)
600                                 usage_attribute.AllowMultiple = field.Value;
601
602                         field = GetNamedValue ("Inherited") as BoolConstant;
603                         if (field != null)
604                                 usage_attribute.Inherited = field.Value;
605
606                         return usage_attribute;
607                 }
608
609                 /// <summary>
610                 /// Returns custom name of indexer
611                 /// </summary>
612                 public string GetIndexerAttributeValue ()
613                 {
614                         if (!arg_resolved)
615                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
616                                 // But because a lot of attribute class code must be rewritten will be better to wait...
617                                 Resolve ();
618
619                         if (resolve_error)
620                                 return null;
621
622                         return ((Constant) PosArguments [0].Expr).GetValue () as string;
623                 }
624
625                 /// <summary>
626                 /// Returns condition of ConditionalAttribute
627                 /// </summary>
628                 public string GetConditionalAttributeValue ()
629                 {
630                         if (!arg_resolved)
631                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
632                                 // But because a lot of attribute class code must be rewritten will be better to wait...
633                                 Resolve ();
634
635                         if (resolve_error)
636                                 return null;
637
638                         return ((Constant) PosArguments[0].Expr).GetValue () as string;
639                 }
640
641                 /// <summary>
642                 /// Creates the instance of ObsoleteAttribute from this attribute instance
643                 /// </summary>
644                 public ObsoleteAttribute GetObsoleteAttribute ()
645                 {
646                         if (!arg_resolved) {
647                                 // corlib only case when obsolete is used before is resolved
648                                 var c = type.MemberDefinition as Class;
649                                 if (c != null && !c.HasMembersDefined)
650                                         c.Define ();
651                                 
652                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
653                                 // But because a lot of attribute class code must be rewritten will be better to wait...
654                                 Resolve ();
655                         }
656
657                         if (resolve_error)
658                                 return null;
659
660                         if (PosArguments == null)
661                                 return new ObsoleteAttribute ();
662
663                         string msg = ((Constant) PosArguments[0].Expr).GetValue () as string;
664                         if (PosArguments.Count == 1)
665                                 return new ObsoleteAttribute (msg);
666
667                         return new ObsoleteAttribute (msg, ((BoolConstant) PosArguments[1].Expr).Value);
668                 }
669
670                 /// <summary>
671                 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
672                 /// before ApplyAttribute. We need to resolve the arguments.
673                 /// This situation occurs when class deps is differs from Emit order.  
674                 /// </summary>
675                 public bool GetClsCompliantAttributeValue ()
676                 {
677                         if (!arg_resolved)
678                                 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
679                                 // But because a lot of attribute class code must be rewritten will be better to wait...
680                                 Resolve ();
681
682                         if (resolve_error)
683                                 return false;
684
685                         return ((BoolConstant) PosArguments[0].Expr).Value;
686                 }
687
688                 public TypeSpec GetCoClassAttributeValue ()
689                 {
690                         if (!arg_resolved)
691                                 Resolve ();
692
693                         if (resolve_error)
694                                 return null;
695
696                         return GetArgumentType ();
697                 }
698
699                 public bool CheckTarget ()
700                 {
701                         string[] valid_targets = Owner.ValidAttributeTargets;
702                         if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
703                                 Target = Owner.AttributeTargets;
704                                 return true;
705                         }
706
707                         // TODO: we can skip the first item
708                         if (Array.Exists (valid_targets, i => i == ExplicitTarget)) {
709                                 switch (ExplicitTarget) {
710                                 case "return": Target = AttributeTargets.ReturnValue; return true;
711                                 case "param": Target = AttributeTargets.Parameter; return true;
712                                 case "field": Target = AttributeTargets.Field; return true;
713                                 case "method": Target = AttributeTargets.Method; return true;
714                                 case "property": Target = AttributeTargets.Property; return true;
715                                 case "module": Target = AttributeTargets.Module; return true;
716                                 }
717                                 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
718                         }
719                                 
720                         StringBuilder sb = new StringBuilder ();
721                         foreach (string s in valid_targets) {
722                                 sb.Append (s);
723                                 sb.Append (", ");
724                         }
725                         sb.Remove (sb.Length - 2, 2);
726                         Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
727                                 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
728                         return false;
729                 }
730
731                 /// <summary>
732                 /// Tests permitted SecurityAction for assembly or other types
733                 /// </summary>
734                 protected virtual bool IsSecurityActionValid (bool for_assembly)
735                 {
736                         SecurityAction action = GetSecurityActionValue ();
737
738                         switch (action) {
739 #pragma warning disable 618
740                         case SecurityAction.Demand:
741                         case SecurityAction.Assert:
742                         case SecurityAction.Deny:
743                         case SecurityAction.PermitOnly:
744                         case SecurityAction.LinkDemand:
745                         case SecurityAction.InheritanceDemand:
746                                 if (!for_assembly)
747                                         return true;
748                                 break;
749
750                         case SecurityAction.RequestMinimum:
751                         case SecurityAction.RequestOptional:
752                         case SecurityAction.RequestRefuse:
753                                 if (for_assembly)
754                                         return true;
755                                 break;
756 #pragma warning restore 618
757
758                         default:
759                                 Error_AttributeEmitError ("SecurityAction is out of range");
760                                 return false;
761                         }
762
763                         Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
764                         return false;
765                 }
766
767                 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
768                 {
769                         return (SecurityAction) ((Constant) PosArguments[0].Expr).GetValue ();
770                 }
771
772                 /// <summary>
773                 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
774                 /// </summary>
775                 /// <returns></returns>
776                 public void ExtractSecurityPermissionSet (MethodSpec ctor, ref SecurityType permissions)
777                 {
778 #if STATIC
779                         object[] values = new object [PosArguments.Count];
780                         for (int i = 0; i < values.Length; ++i)
781                                 values [i] = ((Constant) PosArguments [i].Expr).GetValue ();
782
783                         PropertyInfo[] prop;
784                         object[] prop_values;
785                         if (named_values == null) {
786                                 prop = null;
787                                 prop_values = null;
788                         } else {
789                                 prop = new PropertyInfo[named_values.Count];
790                                 prop_values = new object [named_values.Count];
791                                 for (int i = 0; i < prop.Length; ++i) {
792                                         prop [i] = ((PropertyExpr) named_values [i].Key).PropertyInfo.MetaInfo;
793                                         prop_values [i] = ((Constant) named_values [i].Value.Expr).GetValue ();
794                                 }
795                         }
796
797                         if (permissions == null)
798                                 permissions = new SecurityType ();
799
800                         var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), values, prop, prop_values);
801                         permissions.Add (cab);
802 #else
803                         Type orig_assembly_type = null;
804
805                         if (Type.MemberDefinition is TypeContainer) {
806                                 if (!RootContext.StdLib) {
807                                         orig_assembly_type = System.Type.GetType (Type.GetMetaInfo ().FullName);
808                                 } else {
809                                         string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
810                                         if (orig_version_path == null) {
811                                                 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
812                                                 return;
813                                         }
814
815                                         if (orig_sec_assembly == null) {
816                                                 string file = Path.Combine (orig_version_path, Path.GetFileName (RootContext.OutputFile));
817                                                 orig_sec_assembly = Assembly.LoadFile (file);
818                                         }
819
820                                         orig_assembly_type = orig_sec_assembly.GetType (Type.GetMetaInfo ().FullName, true);
821                                         if (orig_assembly_type == null) {
822                                                 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' " +
823                                                                 "was not found in previous version of assembly");
824                                                 return;
825                                         }
826                                 }
827                         }
828
829                         SecurityAttribute sa;
830                         object[] args;
831
832                         // For all non-selfreferencing security attributes we can avoid all hacks
833                         if (orig_assembly_type == null) {
834                                 args = new object[PosArguments.Count];
835                                 for (int j = 0; j < args.Length; ++j) {
836                                         args[j] = ((Constant) PosArguments[j].Expr).GetValue ();
837                                 }
838
839                                 sa = (SecurityAttribute) Activator.CreateInstance (Type.GetMetaInfo (), args);
840
841                                 if (named_values != null) {
842                                         for (int i = 0; i < named_values.Count; ++i) {
843                                                 PropertyInfo pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
844                                                 pi.SetValue (sa, ((Constant) named_values [i].Value.Expr).GetValue (), null);
845                                         }
846                                 }
847                         } else {
848                                 // HACK: All security attributes have same ctor syntax
849                                 args = new object[] { GetSecurityActionValue () };
850                                 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, args);
851
852                                 // All types are from newly created assembly but for invocation with old one we need to convert them
853                                 if (named_values != null) {
854                                         for (int i = 0; i < named_values.Count; ++i) {
855                                                 PropertyInfo emited_pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
856                                                 // FIXME: We are missing return type filter
857                                                 // TODO: pi can be null
858                                                 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name);
859
860                                                 pi.SetValue (sa, ((Constant) named_values[i].Value.Expr).GetValue (), null);
861                                         }
862                                 }
863                         }
864
865                         IPermission perm;
866                         perm = sa.CreatePermission ();
867                         SecurityAction action = (SecurityAction) args [0];
868
869                         // IS is correct because for corlib we are using an instance from old corlib
870                         if (!(perm is System.Security.CodeAccessPermission)) {
871                                 switch (action) {
872                                 case SecurityAction.Demand:
873                                         action = (SecurityAction)13;
874                                         break;
875                                 case SecurityAction.LinkDemand:
876                                         action = (SecurityAction)14;
877                                         break;
878                                 case SecurityAction.InheritanceDemand:
879                                         action = (SecurityAction)15;
880                                         break;
881                                 }
882                         }
883
884                         if (permissions == null)
885                                 permissions = new SecurityType ();
886
887                         PermissionSet ps;
888                         if (!permissions.TryGetValue (action, out ps)) {
889                                 if (sa is PermissionSetAttribute)
890                                         ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
891                                 else
892                                         ps = new PermissionSet (PermissionState.None);
893
894                                 permissions.Add (action, ps);
895                         } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
896                                 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
897                                 permissions [action] = ps;
898                         }
899                         ps.AddPermission (perm);
900 #endif
901                 }
902
903                 public Constant GetNamedValue (string name)
904                 {
905                         if (named_values == null)
906                                 return null;
907
908                         for (int i = 0; i < named_values.Count; ++i) {
909                                 if (named_values [i].Value.Name == name)
910                                         return named_values [i].Value.Expr as Constant;
911                         }
912
913                         return null;
914                 }
915
916                 public CharSet GetCharSetValue ()
917                 {
918                         return (CharSet)System.Enum.Parse (typeof (CharSet), ((Constant) PosArguments [0].Expr).GetValue ().ToString ());
919                 }
920
921                 public bool HasField (string fieldName)
922                 {
923                         if (named_values == null)
924                                 return false;
925
926                         foreach (var na in named_values) {
927                                 if (na.Value.Name == fieldName)
928                                         return true;
929                         }
930
931                         return false;
932                 }
933
934                 //
935                 // Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value
936                 // 
937                 public bool IsInternalCall ()
938                 {
939                         MethodImplOptions options = 0;
940                         if (PosArguments.Count == 1) {
941                                 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
942                         } else if (HasField ("Value")) {
943                                 var named = GetNamedValue ("Value");
944                                 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ());
945                         }
946
947                         return (options & MethodImplOptions.InternalCall) != 0;
948                 }
949
950                 //
951                 // Returns true for StructLayoutAttribute with LayoutKind.Explicit value
952                 // 
953                 public bool IsExplicitLayoutKind ()
954                 {
955                         if (PosArguments.Count != 1)
956                                 return false;
957
958                         var value = (LayoutKind) System.Enum.Parse (typeof (LayoutKind), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
959                         return value == LayoutKind.Explicit;
960                 }
961
962                 public Constant GetParameterDefaultValue (out TypeSpec type)
963                 {
964                         var expr = PosArguments[0].Expr;
965
966                         if (expr is TypeCast)
967                                 expr = ((TypeCast) expr).Child;
968
969                         type = expr.Type;
970                         return expr as Constant;
971                 }
972
973                 public override bool Equals (object obj)
974                 {
975                         Attribute a = obj as Attribute;
976                         if (a == null)
977                                 return false;
978
979                         return Type == a.Type && Target == a.Target;
980                 }
981
982                 public override int GetHashCode ()
983                 {
984                         return type.GetHashCode () ^ Target.GetHashCode ();
985                 }
986
987                 /// <summary>
988                 /// Emit attribute for Attributable symbol
989                 /// </summary>
990                 public void Emit (Dictionary<Attribute, List<Attribute>> allEmitted)
991                 {
992                         var ctor = Resolve ();
993                         if (ctor == null)
994                                 return;
995
996                         var predefined = context.Module.PredefinedAttributes;
997
998                         AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage);
999                         if ((usage_attr.ValidOn & Target) == 0) {
1000                                 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
1001                                               "It is valid on `{1}' declarations only",
1002                                         GetSignatureForError (), GetValidTargets ());
1003                                 return;
1004                         }
1005
1006                         byte[] cdata;
1007                         if (PosArguments == null && named_values == null) {
1008                                 cdata = AttributeEncoder.Empty;
1009                         } else {
1010                                 AttributeEncoder encoder = new AttributeEncoder ();
1011
1012                                 if (PosArguments != null) {
1013                                         var param_types = ctor.Parameters.Types;
1014                                         for (int j = 0; j < PosArguments.Count; ++j) {
1015                                                 var pt = param_types[j];
1016                                                 var arg_expr = PosArguments[j].Expr;
1017                                                 if (j == 0) {
1018                                                         if (Type == predefined.IndexerName || Type == predefined.Conditional) {
1019                                                                 string v = ((StringConstant) arg_expr).Value;
1020                                                                 if (!Tokenizer.IsValidIdentifier (v) || Tokenizer.IsKeyword (v)) {
1021                                                                         context.Compiler.Report.Error (633, arg_expr.Location,
1022                                                                                 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
1023                                                                 }
1024                                                         } else if (Type == predefined.Guid) {
1025                                                                 try {
1026                                                                         string v = ((StringConstant) arg_expr).Value;
1027                                                                         new Guid (v);
1028                                                                 } catch (Exception e) {
1029                                                                         Error_AttributeEmitError (e.Message);
1030                                                                         return;
1031                                                                 }
1032                                                         } else if (Type == predefined.AttributeUsage) {
1033                                                                 int v = ((IntConstant) ((EnumConstant) arg_expr).Child).Value;
1034                                                                 if (v == 0) {
1035                                                                         context.Compiler.Report.Error (591, Location, "Invalid value for argument to `{0}' attribute",
1036                                                                                 "System.AttributeUsage");
1037                                                                 }
1038                                                         } else if (Type == predefined.MarshalAs) {
1039                                                                 if (PosArguments.Count == 1) {
1040                                                                         var u_type = (UnmanagedType) System.Enum.Parse (typeof (UnmanagedType), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
1041                                                                         if (u_type == UnmanagedType.ByValArray && !(Owner is FieldBase)) {
1042                                                                                 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1043                                                                         }
1044                                                                 }
1045                                                         } else if (Type == predefined.DllImport) {
1046                                                                 if (PosArguments.Count == 1) {
1047                                                                         var value = ((Constant) PosArguments[0].Expr).GetValue () as string;
1048                                                                         if (string.IsNullOrEmpty (value))
1049                                                                                 Error_AttributeEmitError ("DllName cannot be empty");
1050                                                                 }
1051                                                         } else if (Type == predefined.MethodImpl && pt == TypeManager.short_type &&
1052                                                                 !System.Enum.IsDefined (typeof (MethodImplOptions), ((Constant) arg_expr).GetValue ().ToString ())) {
1053                                                                 Error_AttributeEmitError ("Incorrect argument value.");
1054                                                                 return;
1055                                                         }
1056                                                 }
1057
1058                                                 arg_expr.EncodeAttributeValue (context, encoder, pt);
1059                                         }
1060                                 }
1061
1062                                 if (named_values != null) {
1063                                         encoder.Encode ((ushort) named_values.Count);
1064                                         foreach (var na in named_values) {
1065                                                 if (na.Key is FieldExpr)
1066                                                         encoder.Encode ((byte) 0x53);
1067                                                 else
1068                                                         encoder.Encode ((byte) 0x54);
1069
1070                                                 encoder.Encode (na.Key.Type);
1071                                                 encoder.Encode (na.Value.Name);
1072                                                 na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type);
1073                                         }
1074                                 } else {
1075                                         encoder.EncodeEmptyNamedArguments ();
1076                                 }
1077
1078                                 cdata = encoder.ToArray ();
1079                         }
1080
1081                         try {
1082                                 foreach (Attributable target in targets)
1083                                         target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
1084                         } catch (Exception e) {
1085                                 Error_AttributeEmitError (e.Message);
1086                                 return;
1087                         }
1088
1089                         if (!usage_attr.AllowMultiple && allEmitted != null) {
1090                                 if (allEmitted.ContainsKey (this)) {
1091                                         var a = allEmitted [this];
1092                                         if (a == null) {
1093                                                 a = new List<Attribute> (2);
1094                                                 allEmitted [this] = a;
1095                                         }
1096                                         a.Add (this);
1097                                 } else {
1098                                         allEmitted.Add (this, null);
1099                                 }
1100                         }
1101
1102                         if (!RootContext.VerifyClsCompliance)
1103                                 return;
1104
1105                         // Here we are testing attribute arguments for array usage (error 3016)
1106                         if (Owner.IsClsComplianceRequired ()) {
1107                                 if (PosArguments != null)
1108                                         PosArguments.CheckArrayAsAttribute (context.Compiler);
1109                         
1110                                 if (NamedArguments == null)
1111                                         return;
1112
1113                                 NamedArguments.CheckArrayAsAttribute (context.Compiler);
1114                         }
1115                 }
1116
1117                 private Expression GetValue () 
1118                 {
1119                         if (PosArguments == null || PosArguments.Count < 1)
1120                                 return null;
1121
1122                         return PosArguments [0].Expr;
1123                 }
1124
1125                 public string GetString () 
1126                 {
1127                         Expression e = GetValue ();
1128                         if (e is StringConstant)
1129                                 return ((StringConstant)e).Value;
1130                         return null;
1131                 }
1132
1133                 public bool GetBoolean () 
1134                 {
1135                         Expression e = GetValue ();
1136                         if (e is BoolConstant)
1137                                 return ((BoolConstant)e).Value;
1138                         return false;
1139                 }
1140
1141                 public TypeSpec GetArgumentType ()
1142                 {
1143                         TypeOf e = GetValue () as TypeOf;
1144                         if (e == null)
1145                                 return null;
1146                         return e.TypeArgument;
1147                 }
1148
1149                 public override Expression CreateExpressionTree (ResolveContext ec)
1150                 {
1151                         throw new NotSupportedException ("ET");
1152                 }
1153
1154                 protected override Expression DoResolve (ResolveContext ec)
1155                 {
1156                         throw new NotImplementedException ();
1157                 }
1158
1159                 public override void Emit (EmitContext ec)
1160                 {
1161                         throw new NotImplementedException ();
1162                 }
1163         }
1164         
1165
1166         /// <summary>
1167         /// For global attributes (assembly, module) we need special handling.
1168         /// Attributes can be located in the several files
1169         /// </summary>
1170         public class GlobalAttribute : Attribute
1171         {
1172                 public readonly NamespaceEntry ns;
1173
1174                 public GlobalAttribute (NamespaceEntry ns, string target, ATypeNameExpression expression,
1175                                         Arguments[] args, Location loc, bool nameEscaped):
1176                         base (target, expression, args, loc, nameEscaped)
1177                 {
1178                         this.ns = ns;
1179                 }
1180
1181                 void Enter ()
1182                 {
1183                         // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1184                         // each time a new file is parsed.  However, we need to use the NamespaceEntry
1185                         // in effect where the attribute was used.  Since code elsewhere cannot assume
1186                         // that the NamespaceEntry is right, just overwrite it.
1187                         //
1188                         // Precondition: RootContext.ToplevelTypes == null
1189
1190                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1191                                 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1192
1193                         RootContext.ToplevelTypes.NamespaceEntry = ns;
1194                 }
1195
1196                 protected override bool IsSecurityActionValid (bool for_assembly)
1197                 {
1198                         return base.IsSecurityActionValid (true);
1199                 }
1200
1201                 void Leave ()
1202                 {
1203                         RootContext.ToplevelTypes.NamespaceEntry = null;
1204                 }
1205
1206                 protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
1207                 {
1208                         try {
1209                                 Enter ();
1210                                 return base.ResolveAsTypeTerminal (expr, ec);
1211                         }
1212                         finally {
1213                                 Leave ();
1214                         }
1215                 }
1216
1217                 protected override MethodSpec ResolveConstructor (ResolveContext ec)
1218                 {
1219                         try {
1220                                 Enter ();
1221                                 return base.ResolveConstructor (ec);
1222                         }
1223                         finally {
1224                                 Leave ();
1225                         }
1226                 }
1227
1228                 protected override bool ResolveNamedArguments (ResolveContext ec)
1229                 {
1230                         try {
1231                                 Enter ();
1232                                 return base.ResolveNamedArguments (ec);
1233                         }
1234                         finally {
1235                                 Leave ();
1236                         }
1237                 }
1238         }
1239
1240         public class Attributes {
1241                 public readonly List<Attribute> Attrs;
1242
1243                 public Attributes (Attribute a)
1244                 {
1245                         Attrs = new List<Attribute> ();
1246                         Attrs.Add (a);
1247                 }
1248
1249                 public Attributes (List<Attribute> attrs)
1250                 {
1251                         Attrs = attrs;
1252                 }
1253
1254                 public void AddAttributes (List<Attribute> attrs)
1255                 {
1256                         Attrs.AddRange (attrs);
1257                 }
1258
1259                 public void AttachTo (Attributable attributable, IMemberContext context)
1260                 {
1261                         foreach (Attribute a in Attrs)
1262                                 a.AttachTo (attributable, context);
1263                 }
1264
1265                 public Attributes Clone ()
1266                 {
1267                         var al = new List<Attribute> (Attrs.Count);
1268                         foreach (Attribute a in Attrs)
1269                                 al.Add (a.Clone ());
1270
1271                         return new Attributes (al);
1272                 }
1273
1274                 /// <summary>
1275                 /// Checks whether attribute target is valid for the current element
1276                 /// </summary>
1277                 public bool CheckTargets ()
1278                 {
1279                         foreach (Attribute a in Attrs) {
1280                                 if (!a.CheckTarget ())
1281                                         return false;
1282                         }
1283                         return true;
1284                 }
1285
1286                 public Attribute Search (PredefinedAttribute t)
1287                 {
1288                         return Search (null, t);
1289                 }
1290
1291                 public Attribute Search (string explicitTarget, PredefinedAttribute t)
1292                 {
1293                         foreach (Attribute a in Attrs) {
1294                                 if (explicitTarget != null && a.ExplicitTarget != explicitTarget)
1295                                         continue;
1296
1297                                 if (a.ResolveType () == t)
1298                                         return a;
1299                         }
1300                         return null;
1301                 }
1302
1303                 /// <summary>
1304                 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1305                 /// </summary>
1306                 public Attribute[] SearchMulti (PredefinedAttribute t)
1307                 {
1308                         List<Attribute> ar = null;
1309
1310                         foreach (Attribute a in Attrs) {
1311                                 if (a.ResolveType () == t) {
1312                                         if (ar == null)
1313                                                 ar = new List<Attribute> (Attrs.Count);
1314                                         ar.Add (a);
1315                                 }
1316                         }
1317
1318                         return ar == null ? null : ar.ToArray ();
1319                 }
1320
1321                 public void Emit ()
1322                 {
1323                         CheckTargets ();
1324
1325                         Dictionary<Attribute, List<Attribute>> ld = Attrs.Count > 1 ? new Dictionary<Attribute, List<Attribute>> () : null;
1326
1327                         foreach (Attribute a in Attrs)
1328                                 a.Emit (ld);
1329
1330                         if (ld == null || ld.Count == 0)
1331                                 return;
1332
1333                         foreach (var d in ld) {
1334                                 if (d.Value == null)
1335                                         continue;
1336
1337                                 Attribute a = d.Key;
1338
1339                                 foreach (Attribute collision in d.Value)
1340                                         a.Report.SymbolRelatedToPreviousError (collision.Location, "");
1341
1342                                 a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
1343                                         a.GetSignatureForError ());
1344                         }
1345                 }
1346
1347                 public bool Contains (PredefinedAttribute t)
1348                 {
1349                         return Search (t) != null;
1350                 }
1351         }
1352
1353         public sealed class AttributeEncoder
1354         {
1355                 [Flags]
1356                 public enum EncodedTypeProperties
1357                 {
1358                         None = 0,
1359                         DynamicType = 1,
1360                         TypeParameter = 1 << 1
1361                 }
1362
1363                 public static readonly byte[] Empty;
1364
1365                 byte[] buffer;
1366                 int pos;
1367                 const ushort Version = 1;
1368
1369                 static AttributeEncoder ()
1370                 {
1371                         Empty = new byte[4];
1372                         Empty[0] = (byte) Version;
1373                 }
1374
1375                 public AttributeEncoder ()
1376                 {
1377                         buffer = new byte[32];
1378                         Encode (Version);
1379                 }
1380
1381                 public void Encode (bool value)
1382                 {
1383                         Encode (value ? (byte) 1 : (byte) 0);
1384                 }
1385
1386                 public void Encode (byte value)
1387                 {
1388                         if (pos == buffer.Length)
1389                                 Grow (1);
1390
1391                         buffer [pos++] = value;
1392                 }
1393
1394                 public void Encode (sbyte value)
1395                 {
1396                         Encode ((byte) value);
1397                 }
1398
1399                 public void Encode (short value)
1400                 {
1401                         if (pos + 2 > buffer.Length)
1402                                 Grow (2);
1403
1404                         buffer[pos++] = (byte) value;
1405                         buffer[pos++] = (byte) (value >> 8);
1406                 }
1407
1408                 public void Encode (ushort value)
1409                 {
1410                         Encode ((short) value);
1411                 }
1412
1413                 public void Encode (int value)
1414                 {
1415                         if (pos + 4 > buffer.Length)
1416                                 Grow (4);
1417
1418                         buffer[pos++] = (byte) value;
1419                         buffer[pos++] = (byte) (value >> 8);
1420                         buffer[pos++] = (byte) (value >> 16);
1421                         buffer[pos++] = (byte) (value >> 24);
1422                 }
1423
1424                 public void Encode (uint value)
1425                 {
1426                         Encode ((int) value);
1427                 }
1428
1429                 public void Encode (long value)
1430                 {
1431                         if (pos + 8 > buffer.Length)
1432                                 Grow (8);
1433
1434                         buffer[pos++] = (byte) value;
1435                         buffer[pos++] = (byte) (value >> 8);
1436                         buffer[pos++] = (byte) (value >> 16);
1437                         buffer[pos++] = (byte) (value >> 24);
1438                         buffer[pos++] = (byte) (value >> 32);
1439                         buffer[pos++] = (byte) (value >> 40);
1440                         buffer[pos++] = (byte) (value >> 48);
1441                         buffer[pos++] = (byte) (value >> 56);
1442                 }
1443
1444                 public void Encode (ulong value)
1445                 {
1446                         Encode ((long) value);
1447                 }
1448
1449                 public void Encode (float value)
1450                 {
1451                         Encode (SingleConverter.SingleToInt32Bits (value));
1452                 }
1453
1454                 public void Encode (double value)
1455                 {
1456                         Encode (BitConverter.DoubleToInt64Bits (value));
1457                 }
1458
1459                 public void Encode (string value)
1460                 {
1461                         if (value == null) {
1462                                 Encode ((byte) 0xFF);
1463                                 return;
1464                         }
1465
1466                         var buf = Encoding.UTF8.GetBytes(value);
1467                         WriteCompressedValue (buf.Length);
1468
1469                         if (pos + buf.Length > buffer.Length)
1470                                 Grow (buf.Length);
1471
1472                         Buffer.BlockCopy (buf, 0, buffer, pos, buf.Length);
1473                         pos += buf.Length;
1474                 }
1475
1476                 public EncodedTypeProperties Encode (TypeSpec type)
1477                 {
1478                         if (type == TypeManager.bool_type) {
1479                                 Encode ((byte) 0x02);
1480                         } else if (type == TypeManager.char_type) {
1481                                 Encode ((byte) 0x03);
1482                         } else if (type == TypeManager.sbyte_type) {
1483                                 Encode ((byte) 0x04);
1484                         } else if (type == TypeManager.byte_type) {
1485                                 Encode ((byte) 0x05);
1486                         } else if (type == TypeManager.short_type) {
1487                                 Encode ((byte) 0x06);
1488                         } else if (type == TypeManager.ushort_type) {
1489                                 Encode ((byte) 0x07);
1490                         } else if (type == TypeManager.int32_type) {
1491                                 Encode ((byte) 0x08);
1492                         } else if (type == TypeManager.uint32_type) {
1493                                 Encode ((byte) 0x09);
1494                         } else if (type == TypeManager.int64_type) {
1495                                 Encode ((byte) 0x0A);
1496                         } else if (type == TypeManager.uint64_type) {
1497                                 Encode ((byte) 0x0B);
1498                         } else if (type == TypeManager.float_type) {
1499                                 Encode ((byte) 0x0C);
1500                         } else if (type == TypeManager.double_type) {
1501                                 Encode ((byte) 0x0D);
1502                         } else if (type == TypeManager.string_type) {
1503                                 Encode ((byte) 0x0E);
1504                         } else if (type == TypeManager.type_type) {
1505                                 Encode ((byte) 0x50);
1506                         } else if (type == TypeManager.object_type) {
1507                                 Encode ((byte) 0x51);
1508                         } else if (TypeManager.IsEnumType (type)) {
1509                                 Encode ((byte) 0x55);
1510                                 EncodeTypeName (type);
1511                         } else if (type.IsArray) {
1512                                 Encode ((byte) 0x1D);
1513                                 return Encode (TypeManager.GetElementType (type));
1514                         } else if (type == InternalType.Dynamic) {
1515                                 Encode ((byte) 0x51);
1516                                 return EncodedTypeProperties.DynamicType;
1517                         }
1518
1519                         return EncodedTypeProperties.None;
1520                 }
1521
1522                 public void EncodeTypeName (TypeSpec type)
1523                 {
1524                         var old_type = type.GetMetaInfo ();
1525                         Encode (type.MemberDefinition.IsImported ? old_type.AssemblyQualifiedName : old_type.FullName);
1526                 }
1527
1528                 //
1529                 // Encodes single property named argument per call
1530                 //
1531                 public void EncodeNamedPropertyArgument (PropertySpec property, Constant value)
1532                 {
1533                         Encode ((ushort) 1);    // length
1534                         Encode ((byte) 0x54); // property
1535                         Encode (property.MemberType);
1536                         Encode (property.Name);
1537                         value.EncodeAttributeValue (null, this, property.MemberType);
1538                 }
1539
1540                 //
1541                 // Encodes single field named argument per call
1542                 //
1543                 public void EncodeNamedFieldArgument (FieldSpec field, Constant value)
1544                 {
1545                         Encode ((ushort) 1);    // length
1546                         Encode ((byte) 0x53); // field
1547                         Encode (field.MemberType);
1548                         Encode (field.Name);
1549                         value.EncodeAttributeValue (null, this, field.MemberType);
1550                 }
1551
1552                 public void EncodeNamedArguments<T> (T[] members, Constant[] values) where T : MemberSpec, IInterfaceMemberSpec
1553                 {
1554                         Encode ((ushort) members.Length);
1555
1556                         for (int i = 0; i < members.Length; ++i)
1557                         {
1558                                 var member = members[i];
1559
1560                                 if (member.Kind == MemberKind.Field)
1561                                         Encode ((byte) 0x53);
1562                                 else if (member.Kind == MemberKind.Property)
1563                                         Encode ((byte) 0x54);
1564                                 else
1565                                         throw new NotImplementedException (member.Kind.ToString ());
1566
1567                                 Encode (member.MemberType);
1568                                 Encode (member.Name);
1569                                 values [i].EncodeAttributeValue (null, this, member.MemberType);
1570                         }
1571                 }
1572
1573                 public void EncodeEmptyNamedArguments ()
1574                 {
1575                         Encode ((ushort) 0);
1576                 }
1577
1578                 void Grow (int inc)
1579                 {
1580                         int size = System.Math.Max (pos * 4, pos + inc + 2);
1581                         Array.Resize (ref buffer, size);
1582                 }
1583
1584                 void WriteCompressedValue (int value)
1585                 {
1586                         if (value < 0x80) {
1587                                 Encode ((byte) value);
1588                                 return;
1589                         }
1590
1591                         if (value < 0x4000) {
1592                                 Encode ((byte) (0x80 | (value >> 8)));
1593                                 Encode ((byte) value);
1594                                 return;
1595                         }
1596
1597                         Encode (value);
1598                 }
1599
1600                 public byte[] ToArray ()
1601                 {
1602                         byte[] buf = new byte[pos];
1603                         Array.Copy (buffer, buf, pos);
1604                         return buf;
1605                 }
1606         }
1607
1608
1609         /// <summary>
1610         /// Helper class for attribute verification routine.
1611         /// </summary>
1612         static class AttributeTester
1613         {
1614                 public enum Result {
1615                         Ok,
1616                         RefOutArrayError,
1617                         ArrayArrayError
1618                 }
1619
1620                 /// <summary>
1621                 /// Returns true if parameters of two compared methods are CLS-Compliant.
1622                 /// It tests differing only in ref or out, or in array rank.
1623                 /// </summary>
1624                 public static Result AreOverloadedMethodParamsClsCompliant (AParametersCollection pa, AParametersCollection pb) 
1625                 {
1626                         TypeSpec [] types_a = pa.Types;
1627                         TypeSpec [] types_b = pb.Types;
1628                         if (types_a == null || types_b == null)
1629                                 return Result.Ok;
1630
1631                         if (types_a.Length != types_b.Length)
1632                                 return Result.Ok;
1633
1634                         Result result = Result.Ok;
1635                         for (int i = 0; i < types_b.Length; ++i) {
1636                                 TypeSpec aType = types_a [i];
1637                                 TypeSpec bType = types_b [i];
1638
1639                                 var ac_a = aType as ArrayContainer;
1640                                 var ac_b = aType as ArrayContainer;
1641
1642                                 if (ac_a != null && ac_b != null) {
1643                                         if (ac_a.Rank != ac_b.Rank && ac_a.Element == ac_b.Element) {
1644                                                 result = Result.RefOutArrayError;
1645                                                 continue;
1646                                         }
1647
1648                                         if (ac_a.Element.IsArray || ac_b.Element.IsArray) {
1649                                                 result = Result.ArrayArrayError;
1650                                                 continue;
1651                                         }
1652                                 }
1653
1654                                 if (aType != bType)
1655                                         return Result.Ok;
1656
1657                                 const Parameter.Modifier out_ref_mod = (Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
1658                                 if ((pa.FixedParameters[i].ModFlags & out_ref_mod) != (pb.FixedParameters[i].ModFlags & out_ref_mod))
1659                                         result = Result.RefOutArrayError;
1660                         }
1661                         return result;
1662                 }
1663
1664                 /// <summary>
1665                 /// Common method for Obsolete error/warning reporting.
1666                 /// </summary>
1667                 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report)
1668                 {
1669                         if (oa.IsError) {
1670                                 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1671                                 return;
1672                         }
1673
1674                         if (oa.Message == null || oa.Message.Length == 0) {
1675                                 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1676                                 return;
1677                         }
1678                         Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1679                 }
1680         }
1681
1682         //
1683         // Predefined attribute types
1684         //
1685         public class PredefinedAttributes
1686         {
1687                 // Build-in attributes
1688                 public readonly PredefinedAttribute ParamArray;
1689                 public readonly PredefinedAttribute Out;
1690
1691                 // Optional attributes
1692                 public readonly PredefinedAttribute Obsolete;
1693                 public readonly PredefinedAttribute DllImport;
1694                 public readonly PredefinedAttribute MethodImpl;
1695                 public readonly PredefinedAttribute MarshalAs;
1696                 public readonly PredefinedAttribute In;
1697                 public readonly PredefinedAttribute IndexerName;
1698                 public readonly PredefinedAttribute Conditional;
1699                 public readonly PredefinedAttribute CLSCompliant;
1700                 public readonly PredefinedAttribute Security;
1701                 public readonly PredefinedAttribute Required;
1702                 public readonly PredefinedAttribute Guid;
1703                 public readonly PredefinedAttribute AssemblyCulture;
1704                 public readonly PredefinedAttribute AssemblyVersion;
1705                 public readonly PredefinedAttribute AssemblyAlgorithmId;
1706                 public readonly PredefinedAttribute AssemblyFlags;
1707                 public readonly PredefinedAttribute AssemblyFileVersion;
1708                 public readonly PredefinedAttribute ComImport;
1709                 public readonly PredefinedAttribute CoClass;
1710                 public readonly PredefinedAttribute AttributeUsage;
1711                 public readonly PredefinedAttribute DefaultParameterValue;
1712                 public readonly PredefinedAttribute OptionalParameter;
1713                 public readonly PredefinedAttribute UnverifiableCode;
1714
1715                 // New in .NET 2.0
1716                 public readonly PredefinedAttribute DefaultCharset;
1717                 public readonly PredefinedAttribute TypeForwarder;
1718                 public readonly PredefinedAttribute FixedBuffer;
1719                 public readonly PredefinedAttribute CompilerGenerated;
1720                 public readonly PredefinedAttribute InternalsVisibleTo;
1721                 public readonly PredefinedAttribute RuntimeCompatibility;
1722                 public readonly PredefinedAttribute DebuggerHidden;
1723                 public readonly PredefinedAttribute UnsafeValueType;
1724
1725                 // New in .NET 3.5
1726                 public readonly PredefinedAttribute Extension;
1727
1728                 // New in .NET 4.0
1729                 public readonly PredefinedDynamicAttribute Dynamic;
1730
1731                 //
1732                 // Optional types which are used as types and for member lookup
1733                 //
1734                 public readonly PredefinedAttribute DefaultMember;
1735                 public readonly PredefinedDecimalAttribute DecimalConstant;
1736                 public readonly PredefinedAttribute StructLayout;
1737                 public readonly PredefinedAttribute FieldOffset;
1738
1739                 public PredefinedAttributes (ModuleContainer module)
1740                 {
1741                         ParamArray = new PredefinedAttribute (module, "System", "ParamArrayAttribute");
1742                         Out = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OutAttribute");
1743                         ParamArray.Resolve (Location.Null);
1744                         Out.Resolve (Location.Null);
1745
1746                         Obsolete = new PredefinedAttribute (module, "System", "ObsoleteAttribute");
1747                         DllImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DllImportAttribute");
1748                         MethodImpl = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "MethodImplAttribute");
1749                         MarshalAs = new PredefinedAttribute (module, "System.Runtime.InteropServices", "MarshalAsAttribute");
1750                         In = new PredefinedAttribute (module, "System.Runtime.InteropServices", "InAttribute");
1751                         IndexerName = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IndexerNameAttribute");
1752                         Conditional = new PredefinedAttribute (module, "System.Diagnostics", "ConditionalAttribute");
1753                         CLSCompliant = new PredefinedAttribute (module, "System", "CLSCompliantAttribute");
1754                         Security = new PredefinedAttribute (module, "System.Security.Permissions", "SecurityAttribute");
1755                         Required = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1756                         Guid = new PredefinedAttribute (module, "System.Runtime.InteropServices", "GuidAttribute");
1757                         AssemblyCulture = new PredefinedAttribute (module, "System.Reflection", "AssemblyCultureAttribute");
1758                         AssemblyVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyVersionAttribute");
1759                         AssemblyAlgorithmId = new PredefinedAttribute (module, "System.Reflection", "AssemblyAlgorithmIdAttribute");
1760                         AssemblyFlags = new PredefinedAttribute (module, "System.Reflection", "AssemblyFlagsAttribute");
1761                         AssemblyFileVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyFileVersionAttribute");
1762                         ComImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "ComImportAttribute");
1763                         CoClass = new PredefinedAttribute (module, "System.Runtime.InteropServices", "CoClassAttribute");
1764                         AttributeUsage = new PredefinedAttribute (module, "System", "AttributeUsageAttribute");
1765                         DefaultParameterValue = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1766                         OptionalParameter = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OptionalAttribute");
1767                         UnverifiableCode = new PredefinedAttribute (module, "System.Security", "UnverifiableCodeAttribute");
1768
1769                         DefaultCharset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
1770                         TypeForwarder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1771                         FixedBuffer = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "FixedBufferAttribute");
1772                         CompilerGenerated = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1773                         InternalsVisibleTo = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1774                         RuntimeCompatibility = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1775                         DebuggerHidden = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerHiddenAttribute");
1776                         UnsafeValueType = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1777
1778                         Extension = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "ExtensionAttribute");
1779
1780                         Dynamic = new PredefinedDynamicAttribute (module, "System.Runtime.CompilerServices", "DynamicAttribute");
1781
1782                         DefaultMember = new PredefinedAttribute (module, "System.Reflection", "DefaultMemberAttribute");
1783                         DecimalConstant = new PredefinedDecimalAttribute (module, "System.Runtime.CompilerServices", "DecimalConstantAttribute");
1784                         StructLayout = new PredefinedAttribute (module, "System.Runtime.InteropServices", "StructLayoutAttribute");
1785                         FieldOffset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "FieldOffsetAttribute");
1786
1787                         // TODO: Should define only attributes which are used for comparison
1788                         const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
1789                                 System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly;
1790
1791                         foreach (var fi in GetType ().GetFields (all_fields)) {
1792                                 ((PredefinedAttribute) fi.GetValue (this)).Define ();
1793                         }
1794                 }
1795         }
1796
1797         public class PredefinedAttribute : PredefinedType
1798         {
1799                 protected MethodSpec ctor;
1800                 List<PropertySpec> properties;
1801
1802                 public PredefinedAttribute (ModuleContainer module, string ns, string name)
1803                         : base (module, MemberKind.Class, ns, name)
1804                 {
1805                 }
1806
1807                 #region Properties
1808
1809                 public MethodSpec Constructor {
1810                         get {
1811                                 return ctor;
1812                         }
1813                 }
1814
1815                 #endregion
1816
1817                 public static bool operator == (TypeSpec type, PredefinedAttribute pa)
1818                 {
1819                         return type == pa.type && pa.type != null;
1820                 }
1821
1822                 public static bool operator != (TypeSpec type, PredefinedAttribute pa)
1823                 {
1824                         return type != pa.type;
1825                 }
1826
1827                 public override int GetHashCode ()
1828                 {
1829                         return base.GetHashCode ();
1830                 }
1831
1832                 public override bool Equals (object obj)
1833                 {
1834                         throw new NotSupportedException ();
1835                 }
1836
1837                 public void EmitAttribute (ConstructorBuilder builder)
1838                 {
1839                         if (ResolveBuilder ())
1840                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1841                 }
1842
1843                 public void EmitAttribute (MethodBuilder builder)
1844                 {
1845                         if (ResolveBuilder ())
1846                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1847                 }
1848
1849                 public void EmitAttribute (PropertyBuilder builder)
1850                 {
1851                         if (ResolveBuilder ())
1852                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1853                 }
1854
1855                 public void EmitAttribute (FieldBuilder builder)
1856                 {
1857                         if (ResolveBuilder ())
1858                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1859                 }
1860
1861                 public void EmitAttribute (FieldBuilder builder, AttributeEncoder argsEncoded)
1862                 {
1863                         builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1864                 }
1865
1866                 public void EmitAttribute (TypeBuilder builder)
1867                 {
1868                         if (ResolveBuilder ())
1869                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1870                 }
1871
1872                 public void EmitAttribute (TypeBuilder builder, AttributeEncoder argsEncoded)
1873                 {
1874                         builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1875                 }
1876
1877                 public void EmitAttribute (AssemblyBuilder builder)
1878                 {
1879                         if (ResolveBuilder ())
1880                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1881                 }
1882
1883                 public void EmitAttribute (ModuleBuilder builder)
1884                 {
1885                         if (ResolveBuilder ())
1886                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1887                 }
1888
1889                 public void EmitAttribute (ParameterBuilder builder)
1890                 {
1891                         if (ResolveBuilder ())
1892                                 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1893                 }
1894
1895                 public void EmitAttribute (ParameterBuilder builder, AttributeEncoder argsEncoded)
1896                 {
1897                         builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1898                 }
1899
1900                 ConstructorInfo GetCtorMetaInfo ()
1901                 {
1902                         return (ConstructorInfo) ctor.GetMetaInfo ();
1903                 }
1904
1905                 public PropertySpec GetProperty (string name, TypeSpec memberType, Location loc)
1906                 {
1907                         PropertySpec spec;
1908
1909                         if (properties != null) {
1910                                 spec = properties.Find (l => l.Name == name);
1911                         } else {
1912                                 spec = null;
1913                         }
1914
1915                         if (spec == null) {
1916                                 spec = TypeManager.GetPredefinedProperty (type, name, loc, memberType);
1917
1918                                 if (spec != null) {
1919                                         if (properties == null) {
1920                                                 properties = new List<PropertySpec> ();
1921                                         }
1922
1923                                         properties.Add (spec);
1924                                 }
1925                         }
1926
1927                         return spec;
1928                 }
1929
1930                 public bool ResolveBuilder ()
1931                 {
1932                         if (ctor != null)
1933                                 return true;
1934
1935                         //
1936                         // Handle all parameter-less attributes as optional
1937                         //
1938                         if (!IsDefined)
1939                                 return false;
1940
1941                         ctor = TypeManager.GetPredefinedConstructor (type, Location.Null, TypeSpec.EmptyTypes);
1942                         return ctor != null;
1943                 }
1944
1945                 public bool ResolveConstructor (Location loc, params TypeSpec[] argType)
1946                 {
1947                         if (ctor != null)
1948                                 throw new InternalErrorException ("Predefined ctor redefined");
1949
1950                         if (Resolve (loc) == null)
1951                                 return false;
1952
1953                         ctor = TypeManager.GetPredefinedConstructor (type, loc, argType);
1954                         return ctor != null;
1955                 }
1956         }
1957
1958         public class PredefinedDecimalAttribute : PredefinedAttribute
1959         {
1960                 public PredefinedDecimalAttribute (ModuleContainer module, string ns, string name)
1961                         : base (module, ns, name)
1962                 {
1963                 }
1964
1965                 public void EmitAttribute (ParameterBuilder builder, decimal value, Location loc)
1966                 {
1967                         if (Resolve (loc) == null)
1968                                 return;
1969
1970                         if (ctor == null && !ResolveConstructor (loc, TypeManager.byte_type, TypeManager.byte_type, TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
1971                                 return;
1972
1973                         int[] bits = decimal.GetBits (value);
1974                         AttributeEncoder encoder = new AttributeEncoder ();
1975                         encoder.Encode ((byte) (bits[3] >> 16));
1976                         encoder.Encode ((byte) (bits[3] >> 31));
1977                         encoder.Encode ((uint) bits[2]);
1978                         encoder.Encode ((uint) bits[1]);
1979                         encoder.Encode ((uint) bits[0]);
1980                         encoder.EncodeEmptyNamedArguments ();
1981
1982                         EmitAttribute (builder, encoder);
1983                 }
1984
1985                 public void EmitAttribute (FieldBuilder builder, decimal value, Location loc)
1986                 {
1987                         if (Resolve (loc) == null)
1988                                 return;
1989
1990                         if (ctor == null && !ResolveConstructor (loc, TypeManager.byte_type, TypeManager.byte_type, TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
1991                                 return;
1992
1993                         int[] bits = decimal.GetBits (value);
1994                         AttributeEncoder encoder = new AttributeEncoder ();
1995                         encoder.Encode ((byte) (bits[3] >> 16));
1996                         encoder.Encode ((byte) (bits[3] >> 31));
1997                         encoder.Encode ((uint) bits[2]);
1998                         encoder.Encode ((uint) bits[1]);
1999                         encoder.Encode ((uint) bits[0]);
2000                         encoder.EncodeEmptyNamedArguments ();
2001
2002                         EmitAttribute (builder, encoder);
2003                 }
2004         }
2005
2006         public class PredefinedDynamicAttribute : PredefinedAttribute
2007         {
2008                 MethodSpec tctor;
2009
2010                 public PredefinedDynamicAttribute (ModuleContainer module, string ns, string name)
2011                         : base (module, ns, name)
2012                 {
2013                 }
2014
2015                 public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
2016                 {
2017                         if (ResolveTransformationCtor (loc)) {
2018                                 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
2019                                 builder.SetCustomAttribute (cab);
2020                         }
2021                 }
2022
2023                 public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
2024                 {
2025                         if (ResolveTransformationCtor (loc)) {
2026                                 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
2027                                 builder.SetCustomAttribute (cab);
2028                         }
2029                 }
2030
2031                 public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
2032                 {
2033                         if (ResolveTransformationCtor (loc)) {
2034                                 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
2035                                 builder.SetCustomAttribute (cab);
2036                         }
2037                 }
2038
2039                 public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
2040                 {
2041                         if (ResolveTransformationCtor (loc)) {
2042                                 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
2043                                 builder.SetCustomAttribute (cab);
2044                         }
2045                 }
2046
2047                 //
2048                 // When any element of the type is a dynamic type
2049                 //
2050                 // This method builds a transformation array for dynamic types
2051                 // used in places where DynamicAttribute cannot be applied to.
2052                 // It uses bool flag when type is of dynamic type and each
2053                 // section always starts with "false" for some reason.
2054                 //
2055                 // LAMESPEC: This should be part of C# specification
2056                 // 
2057                 // Example: Func<dynamic, int, dynamic[]>
2058                 // Transformation: { false, true, false, false, true }
2059                 //
2060                 static bool[] GetTransformationFlags (TypeSpec t)
2061                 {
2062                         bool[] element;
2063                         var ac = t as ArrayContainer;
2064                         if (ac != null) {
2065                                 element = GetTransformationFlags (ac.Element);
2066                                 if (element == null)
2067                                         return null;
2068
2069                                 bool[] res = new bool[element.Length + 1];
2070                                 res[0] = false;
2071                                 Array.Copy (element, 0, res, 1, element.Length);
2072                                 return res;
2073                         }
2074
2075                         if (t == null)
2076                                 return null;
2077
2078                         if (t.IsGeneric) {
2079                                 List<bool> transform = null;
2080                                 var targs = t.TypeArguments;
2081                                 for (int i = 0; i < targs.Length; ++i) {
2082                                         element = GetTransformationFlags (targs[i]);
2083                                         if (element != null) {
2084                                                 if (transform == null) {
2085                                                         transform = new List<bool> ();
2086                                                         for (int ii = 0; ii <= i; ++ii)
2087                                                                 transform.Add (false);
2088                                                 }
2089
2090                                                 transform.AddRange (element);
2091                                         } else if (transform != null) {
2092                                                 transform.Add (false);
2093                                         }
2094                                 }
2095
2096                                 if (transform != null)
2097                                         return transform.ToArray ();
2098                         }
2099
2100                         if (t == InternalType.Dynamic)
2101                                 return new bool[] { true };
2102
2103                         return null;
2104                 }
2105
2106                 bool ResolveTransformationCtor (Location loc)
2107                 {
2108                         if (tctor != null)
2109                                 return true;
2110
2111                         if (Resolve (loc) == null)
2112                                 return false;
2113
2114                         tctor = TypeManager.GetPredefinedConstructor (type, Location.Null, ArrayContainer.MakeType (TypeManager.bool_type));
2115                         return tctor != null;
2116                 }
2117         }
2118 }