2 // attribute.cs: Attribute Handler
4 // Author: Ravi Pratap (ravi@ximian.com)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Runtime.InteropServices;
16 using System.Runtime.CompilerServices;
17 using System.Security;
18 using System.Security.Permissions;
23 using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
24 using IKVM.Reflection;
25 using IKVM.Reflection.Emit;
27 using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
28 using System.Reflection;
29 using System.Reflection.Emit;
32 namespace Mono.CSharp {
35 /// Base class for objects that can have Attributes applied to them.
37 public abstract class Attributable {
39 // Holds all attributes attached to this element
41 protected Attributes attributes;
43 public void AddAttributes (Attributes attrs, IMemberContext context)
48 if (attributes == null)
51 throw new NotImplementedException ();
53 attributes.AttachTo (this, context);
56 public Attributes OptAttributes {
66 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
68 public abstract void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa);
71 /// Returns one AttributeTarget for this element.
73 public abstract AttributeTargets AttributeTargets { get; }
75 public abstract bool IsClsComplianceRequired ();
78 /// Gets list of valid attribute targets for explicit target declaration.
79 /// The first array item is default target. Don't break this rule.
81 public abstract string[] ValidAttributeTargets { get; }
84 public class Attribute : Expression
86 public readonly string ExplicitTarget;
87 public AttributeTargets Target;
88 readonly ATypeNameExpression expression;
90 Arguments PosArguments;
91 Arguments NamedArguments;
95 readonly bool nameEscaped;
98 // An attribute can be attached to multiple targets (e.g. multiple fields)
100 protected Attributable[] targets;
103 // A member context for the attribute, it's much easier to hold it here
104 // than trying to pull it during resolve
106 IMemberContext context;
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];
112 List<KeyValuePair<MemberExpr, NamedArgument>> named_values;
114 // Cache for parameter-less attributes
115 static Dictionary<TypeSpec, MethodSpec> att_cache;
117 public Attribute (string target, ATypeNameExpression expr, Arguments[] args, Location loc, bool nameEscaped)
119 this.expression = expr;
121 PosArguments = args [0];
122 NamedArguments = args [1];
125 ExplicitTarget = target;
126 this.nameEscaped = nameEscaped;
129 void AddModuleCharSet (ResolveContext rc)
131 const string dll_import_char_set = "CharSet";
134 // Only when not customized by user
136 if (HasField (dll_import_char_set))
139 if (!rc.Module.PredefinedTypes.CharSet.IsDefined) {
143 if (NamedArguments == null)
144 NamedArguments = new Arguments (1);
146 var value = Constant.CreateConstant (rc.Module.PredefinedTypes.CharSet.TypeSpec, rc.Module.DefaultCharSet, Location);
147 NamedArguments.Add (new NamedArgument (dll_import_char_set, loc, value));
150 public Attribute Clone ()
152 Attribute a = new Attribute (ExplicitTarget, expression, null, loc, nameEscaped);
153 a.PosArguments = PosArguments;
154 a.NamedArguments = NamedArguments;
163 public static void Reset ()
165 att_cache = new Dictionary<TypeSpec, MethodSpec> ();
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.
173 public void AttachTo (Attributable target, IMemberContext context)
175 if (this.targets == null) {
176 this.targets = new Attributable[] { target };
177 this.context = context;
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;
187 // No need to update context, different targets cannot have
188 // different contexts, it's enough to remove same attributes
189 // from secondary members.
191 target.OptAttributes = null;
194 public ResolveContext CreateResolveContext ()
196 return new ResolveContext (context, ResolveContext.Options.ConstantScope);
199 static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name)
201 rc.Report.Error (617, name.Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
202 "must be fields which are not readonly, static, const or read-write properties which are " +
203 "public and not static",
207 static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name)
209 rc.Report.Error (655, name.Location,
210 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
214 public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc)
216 context.Module.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression");
219 public void Error_MissingGuidAttribute ()
221 Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
224 public void Error_MisusedExtensionAttribute ()
226 Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
229 public void Error_MisusedDynamicAttribute ()
231 Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
235 /// This is rather hack. We report many emit attribute error with same error to be compatible with
236 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
238 public void Error_AttributeEmitError (string inner)
240 Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
241 TypeManager.CSharpName (Type), inner);
244 public void Error_InvalidSecurityParent ()
246 Error_AttributeEmitError ("it is attached to invalid parent");
255 protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
257 return expr.ResolveAsTypeTerminal (ec, false);
260 TypeSpec ResolvePossibleAttributeType (ATypeNameExpression expr, ref bool is_attr)
262 TypeExpr te = ResolveAsTypeTerminal (expr, context);
266 TypeSpec t = te.Type;
270 Report.SymbolRelatedToPreviousError (t);
271 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
277 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
279 void ResolveAttributeType ()
281 SessionReportPrinter resolve_printer = new SessionReportPrinter ();
282 ReportPrinter prev_recorder = context.Module.Compiler.Report.SetPrinter (resolve_printer);
284 bool t1_is_attr = false;
285 bool t2_is_attr = false;
287 ATypeNameExpression expanded = null;
290 t1 = ResolvePossibleAttributeType (expression, ref t1_is_attr);
295 expanded = (ATypeNameExpression) expression.Clone (null);
296 expanded.Name += "Attribute";
298 t2 = ResolvePossibleAttributeType (expanded, ref t2_is_attr);
301 resolve_printer.EndSession ();
303 context.Module.Compiler.Report.SetPrinter (prev_recorder);
306 if (t1_is_attr && t2_is_attr) {
307 Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
308 GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ());
309 resolve_error = true;
323 resolve_printer.Merge (prev_recorder);
324 resolve_error = true;
327 public virtual TypeSpec ResolveType ()
329 if (Type == null && !resolve_error)
330 ResolveAttributeType ();
334 public override string GetSignatureForError ()
337 return TypeManager.CSharpName (Type);
339 return expression.GetSignatureForError ();
342 public bool HasSecurityAttribute {
344 PredefinedAttribute pa = context.Module.PredefinedAttributes.Security;
345 return pa.IsDefined && TypeSpec.IsBaseClass (type, pa.TypeSpec, false);
349 public bool IsValidSecurityAttribute ()
351 return HasSecurityAttribute && IsSecurityActionValid (false);
354 static bool IsValidArgumentType (TypeSpec t)
357 var ac = (ArrayContainer) t;
364 switch (t.BuildinType) {
365 case BuildinTypeSpec.Type.Int:
366 case BuildinTypeSpec.Type.UInt:
367 case BuildinTypeSpec.Type.Long:
368 case BuildinTypeSpec.Type.ULong:
369 case BuildinTypeSpec.Type.Float:
370 case BuildinTypeSpec.Type.Double:
371 case BuildinTypeSpec.Type.Char:
372 case BuildinTypeSpec.Type.Short:
373 case BuildinTypeSpec.Type.Bool:
374 case BuildinTypeSpec.Type.SByte:
375 case BuildinTypeSpec.Type.Byte:
376 case BuildinTypeSpec.Type.UShort:
378 case BuildinTypeSpec.Type.String:
379 case BuildinTypeSpec.Type.Object:
380 case BuildinTypeSpec.Type.Dynamic:
381 case BuildinTypeSpec.Type.Type:
388 // TODO: Don't use this ambiguous value
390 get { return expression.Name; }
393 public Report Report {
394 get { return context.Module.Compiler.Report; }
397 public MethodSpec Resolve ()
402 resolve_error = true;
406 ResolveAttributeType ();
411 if (Type.IsAbstract) {
412 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
416 ObsoleteAttribute obsolete_attr = Type.GetAttributeObsolete ();
417 if (obsolete_attr != null) {
418 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location, Report);
422 // Try if the attribute is simple has been resolved before
423 if (PosArguments == null && NamedArguments == null) {
424 if (att_cache.TryGetValue (Type, out ctor)) {
425 resolve_error = false;
430 ResolveContext rc = CreateResolveContext ();
431 ctor = ResolveConstructor (rc);
437 // Add [module: DefaultCharSet] to all DllImport import attributes
439 var module = context.Module;
440 if (Type == module.PredefinedAttributes.DllImport && module.HasDefaultCharSet) {
441 AddModuleCharSet (rc);
444 if (NamedArguments != null && !ResolveNamedArguments (rc)) {
448 resolve_error = false;
452 protected virtual MethodSpec ResolveConstructor (ResolveContext ec)
454 if (PosArguments != null) {
456 PosArguments.Resolve (ec, out dynamic);
458 Error_AttributeArgumentIsDynamic (ec.MemberContext, loc);
463 return ConstructorLookup (ec, Type, ref PosArguments, loc);
466 protected virtual bool ResolveNamedArguments (ResolveContext ec)
468 int named_arg_count = NamedArguments.Count;
469 var seen_names = new List<string> (named_arg_count);
471 named_values = new List<KeyValuePair<MemberExpr, NamedArgument>> (named_arg_count);
473 foreach (NamedArgument a in NamedArguments) {
474 string name = a.Name;
475 if (seen_names.Contains (name)) {
476 ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name);
480 seen_names.Add (name);
484 Expression member = Expression.MemberLookup (ec, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
486 if (member == null) {
487 member = Expression.MemberLookup (null, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
489 if (member != null) {
490 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
491 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
497 Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name);
501 if (!(member is PropertyExpr || member is FieldExpr)) {
502 Error_InvalidNamedArgument (ec, a);
506 ObsoleteAttribute obsolete_attr;
508 if (member is PropertyExpr) {
509 var pi = ((PropertyExpr) member).PropertyInfo;
511 if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) {
512 ec.Report.SymbolRelatedToPreviousError (pi);
513 Error_InvalidNamedArgument (ec, a);
517 if (!IsValidArgumentType (member.Type)) {
518 ec.Report.SymbolRelatedToPreviousError (pi);
519 Error_InvalidNamedArgumentType (ec, a);
523 obsolete_attr = pi.GetAttributeObsolete ();
524 pi.MemberDefinition.SetIsAssigned ();
526 var fi = ((FieldExpr) member).Spec;
528 if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) {
529 Error_InvalidNamedArgument (ec, a);
533 if (!IsValidArgumentType (member.Type)) {
534 ec.Report.SymbolRelatedToPreviousError (fi);
535 Error_InvalidNamedArgumentType (ec, a);
539 obsolete_attr = fi.GetAttributeObsolete ();
540 fi.MemberDefinition.SetIsAssigned ();
543 if (obsolete_attr != null && !context.IsObsolete)
544 AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location, Report);
546 if (a.Type != member.Type) {
547 a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location);
551 named_values.Add (new KeyValuePair<MemberExpr, NamedArgument> ((MemberExpr) member, a));
558 /// Get a string containing a list of valid targets for the attribute 'attr'
560 public string GetValidTargets ()
562 StringBuilder sb = new StringBuilder ();
563 AttributeTargets targets = Type.GetAttributeUsage (context.Module.PredefinedAttributes.AttributeUsage).ValidOn;
565 if ((targets & AttributeTargets.Assembly) != 0)
566 sb.Append ("assembly, ");
568 if ((targets & AttributeTargets.Module) != 0)
569 sb.Append ("module, ");
571 if ((targets & AttributeTargets.Class) != 0)
572 sb.Append ("class, ");
574 if ((targets & AttributeTargets.Struct) != 0)
575 sb.Append ("struct, ");
577 if ((targets & AttributeTargets.Enum) != 0)
578 sb.Append ("enum, ");
580 if ((targets & AttributeTargets.Constructor) != 0)
581 sb.Append ("constructor, ");
583 if ((targets & AttributeTargets.Method) != 0)
584 sb.Append ("method, ");
586 if ((targets & AttributeTargets.Property) != 0)
587 sb.Append ("property, indexer, ");
589 if ((targets & AttributeTargets.Field) != 0)
590 sb.Append ("field, ");
592 if ((targets & AttributeTargets.Event) != 0)
593 sb.Append ("event, ");
595 if ((targets & AttributeTargets.Interface) != 0)
596 sb.Append ("interface, ");
598 if ((targets & AttributeTargets.Parameter) != 0)
599 sb.Append ("parameter, ");
601 if ((targets & AttributeTargets.Delegate) != 0)
602 sb.Append ("delegate, ");
604 if ((targets & AttributeTargets.ReturnValue) != 0)
605 sb.Append ("return, ");
607 if ((targets & AttributeTargets.GenericParameter) != 0)
608 sb.Append ("type parameter, ");
610 return sb.Remove (sb.Length - 2, 2).ToString ();
613 public AttributeUsageAttribute GetAttributeUsageAttribute ()
616 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
617 // But because a lot of attribute class code must be rewritten will be better to wait...
621 return DefaultUsageAttribute;
623 AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)((Constant) PosArguments [0].Expr).GetValue ());
625 var field = GetNamedValue ("AllowMultiple") as BoolConstant;
627 usage_attribute.AllowMultiple = field.Value;
629 field = GetNamedValue ("Inherited") as BoolConstant;
631 usage_attribute.Inherited = field.Value;
633 return usage_attribute;
637 /// Returns custom name of indexer
639 public string GetIndexerAttributeValue ()
642 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
643 // But because a lot of attribute class code must be rewritten will be better to wait...
649 return ((Constant) PosArguments [0].Expr).GetValue () as string;
653 /// Returns condition of ConditionalAttribute
655 public string GetConditionalAttributeValue ()
658 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
659 // But because a lot of attribute class code must be rewritten will be better to wait...
665 return ((Constant) PosArguments[0].Expr).GetValue () as string;
669 /// Creates the instance of ObsoleteAttribute from this attribute instance
671 public ObsoleteAttribute GetObsoleteAttribute ()
674 // corlib only case when obsolete is used before is resolved
675 var c = type.MemberDefinition as Class;
676 if (c != null && !c.HasMembersDefined)
679 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
680 // But because a lot of attribute class code must be rewritten will be better to wait...
687 if (PosArguments == null)
688 return new ObsoleteAttribute ();
690 string msg = ((Constant) PosArguments[0].Expr).GetValue () as string;
691 if (PosArguments.Count == 1)
692 return new ObsoleteAttribute (msg);
694 return new ObsoleteAttribute (msg, ((BoolConstant) PosArguments[1].Expr).Value);
698 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
699 /// before ApplyAttribute. We need to resolve the arguments.
700 /// This situation occurs when class deps is differs from Emit order.
702 public bool GetClsCompliantAttributeValue ()
705 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
706 // But because a lot of attribute class code must be rewritten will be better to wait...
712 return ((BoolConstant) PosArguments[0].Expr).Value;
715 public TypeSpec GetCoClassAttributeValue ()
723 return GetArgumentType ();
726 public bool CheckTarget ()
728 string[] valid_targets = Owner.ValidAttributeTargets;
729 if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
730 Target = Owner.AttributeTargets;
734 // TODO: we can skip the first item
735 if (Array.Exists (valid_targets, i => i == ExplicitTarget)) {
736 switch (ExplicitTarget) {
737 case "return": Target = AttributeTargets.ReturnValue; return true;
738 case "param": Target = AttributeTargets.Parameter; return true;
739 case "field": Target = AttributeTargets.Field; return true;
740 case "method": Target = AttributeTargets.Method; return true;
741 case "property": Target = AttributeTargets.Property; return true;
742 case "module": Target = AttributeTargets.Module; return true;
744 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
747 StringBuilder sb = new StringBuilder ();
748 foreach (string s in valid_targets) {
752 sb.Remove (sb.Length - 2, 2);
753 Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
754 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
759 /// Tests permitted SecurityAction for assembly or other types
761 protected virtual bool IsSecurityActionValid (bool for_assembly)
763 SecurityAction action = GetSecurityActionValue ();
766 #pragma warning disable 618
767 case SecurityAction.Demand:
768 case SecurityAction.Assert:
769 case SecurityAction.Deny:
770 case SecurityAction.PermitOnly:
771 case SecurityAction.LinkDemand:
772 case SecurityAction.InheritanceDemand:
777 case SecurityAction.RequestMinimum:
778 case SecurityAction.RequestOptional:
779 case SecurityAction.RequestRefuse:
783 #pragma warning restore 618
786 Error_AttributeEmitError ("SecurityAction is out of range");
790 Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
794 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
796 return (SecurityAction) ((Constant) PosArguments[0].Expr).GetValue ();
800 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
802 /// <returns></returns>
803 public void ExtractSecurityPermissionSet (MethodSpec ctor, ref SecurityType permissions)
806 object[] values = new object [PosArguments.Count];
807 for (int i = 0; i < values.Length; ++i)
808 values [i] = ((Constant) PosArguments [i].Expr).GetValue ();
811 object[] prop_values;
812 if (named_values == null) {
816 prop = new PropertyInfo[named_values.Count];
817 prop_values = new object [named_values.Count];
818 for (int i = 0; i < prop.Length; ++i) {
819 prop [i] = ((PropertyExpr) named_values [i].Key).PropertyInfo.MetaInfo;
820 prop_values [i] = ((Constant) named_values [i].Value.Expr).GetValue ();
824 if (permissions == null)
825 permissions = new SecurityType ();
827 var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), values, prop, prop_values);
828 permissions.Add (cab);
830 throw new NotSupportedException ();
834 public Constant GetNamedValue (string name)
836 if (named_values == null)
839 for (int i = 0; i < named_values.Count; ++i) {
840 if (named_values [i].Value.Name == name)
841 return named_values [i].Value.Expr as Constant;
847 public CharSet GetCharSetValue ()
849 return (CharSet)System.Enum.Parse (typeof (CharSet), ((Constant) PosArguments [0].Expr).GetValue ().ToString ());
852 public bool HasField (string fieldName)
854 if (named_values == null)
857 foreach (var na in named_values) {
858 if (na.Value.Name == fieldName)
866 // Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value
868 public bool IsInternalCall ()
870 MethodImplOptions options = 0;
871 if (PosArguments.Count == 1) {
872 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
873 } else if (HasField ("Value")) {
874 var named = GetNamedValue ("Value");
875 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ());
878 return (options & MethodImplOptions.InternalCall) != 0;
882 // Returns true for StructLayoutAttribute with LayoutKind.Explicit value
884 public bool IsExplicitLayoutKind ()
886 if (PosArguments == null || PosArguments.Count != 1)
889 var value = (LayoutKind) System.Enum.Parse (typeof (LayoutKind), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
890 return value == LayoutKind.Explicit;
893 public Expression GetParameterDefaultValue ()
895 if (PosArguments == null)
898 return PosArguments[0].Expr;
901 public override bool Equals (object obj)
903 Attribute a = obj as Attribute;
907 return Type == a.Type && Target == a.Target;
910 public override int GetHashCode ()
912 return type.GetHashCode () ^ Target.GetHashCode ();
916 /// Emit attribute for Attributable symbol
918 public void Emit (Dictionary<Attribute, List<Attribute>> allEmitted)
920 var ctor = Resolve ();
924 var predefined = context.Module.PredefinedAttributes;
926 AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage);
927 if ((usage_attr.ValidOn & Target) == 0) {
928 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
929 "It is valid on `{1}' declarations only",
930 GetSignatureForError (), GetValidTargets ());
935 if (PosArguments == null && named_values == null) {
936 cdata = AttributeEncoder.Empty;
938 AttributeEncoder encoder = new AttributeEncoder ();
940 if (PosArguments != null) {
941 var param_types = ctor.Parameters.Types;
942 for (int j = 0; j < PosArguments.Count; ++j) {
943 var pt = param_types[j];
944 var arg_expr = PosArguments[j].Expr;
946 if (Type == predefined.IndexerName || Type == predefined.Conditional) {
947 string v = ((StringConstant) arg_expr).Value;
948 if (!Tokenizer.IsValidIdentifier (v) || Tokenizer.IsKeyword (v)) {
949 context.Module.Compiler.Report.Error (633, arg_expr.Location,
950 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
952 } else if (Type == predefined.Guid) {
954 string v = ((StringConstant) arg_expr).Value;
956 } catch (Exception e) {
957 Error_AttributeEmitError (e.Message);
960 } else if (Type == predefined.AttributeUsage) {
961 int v = ((IntConstant) ((EnumConstant) arg_expr).Child).Value;
963 context.Module.Compiler.Report.Error (591, Location, "Invalid value for argument to `{0}' attribute",
964 "System.AttributeUsage");
966 } else if (Type == predefined.MarshalAs) {
967 if (PosArguments.Count == 1) {
968 var u_type = (UnmanagedType) System.Enum.Parse (typeof (UnmanagedType), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
969 if (u_type == UnmanagedType.ByValArray && !(Owner is FieldBase)) {
970 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
973 } else if (Type == predefined.DllImport) {
974 if (PosArguments.Count == 1) {
975 var value = ((Constant) PosArguments[0].Expr).GetValue () as string;
976 if (string.IsNullOrEmpty (value))
977 Error_AttributeEmitError ("DllName cannot be empty");
979 } else if (Type == predefined.MethodImpl && pt.BuildinType == BuildinTypeSpec.Type.Short &&
980 !System.Enum.IsDefined (typeof (MethodImplOptions), ((Constant) arg_expr).GetValue ().ToString ())) {
981 Error_AttributeEmitError ("Incorrect argument value.");
986 arg_expr.EncodeAttributeValue (context, encoder, pt);
990 if (named_values != null) {
991 encoder.Encode ((ushort) named_values.Count);
992 foreach (var na in named_values) {
993 if (na.Key is FieldExpr)
994 encoder.Encode ((byte) 0x53);
996 encoder.Encode ((byte) 0x54);
998 encoder.Encode (na.Key.Type);
999 encoder.Encode (na.Value.Name);
1000 na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type);
1003 encoder.EncodeEmptyNamedArguments ();
1006 cdata = encoder.ToArray ();
1010 foreach (Attributable target in targets)
1011 target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
1012 } catch (Exception e) {
1013 Error_AttributeEmitError (e.Message);
1017 if (!usage_attr.AllowMultiple && allEmitted != null) {
1018 if (allEmitted.ContainsKey (this)) {
1019 var a = allEmitted [this];
1021 a = new List<Attribute> (2);
1022 allEmitted [this] = a;
1026 allEmitted.Add (this, null);
1030 if (!context.Module.Compiler.Settings.VerifyClsCompliance)
1033 // Here we are testing attribute arguments for array usage (error 3016)
1034 if (Owner.IsClsComplianceRequired ()) {
1035 if (PosArguments != null)
1036 PosArguments.CheckArrayAsAttribute (context.Module.Compiler);
1038 if (NamedArguments == null)
1041 NamedArguments.CheckArrayAsAttribute (context.Module.Compiler);
1045 private Expression GetValue ()
1047 if (PosArguments == null || PosArguments.Count < 1)
1050 return PosArguments [0].Expr;
1053 public string GetString ()
1055 Expression e = GetValue ();
1056 if (e is StringConstant)
1057 return ((StringConstant)e).Value;
1061 public bool GetBoolean ()
1063 Expression e = GetValue ();
1064 if (e is BoolConstant)
1065 return ((BoolConstant)e).Value;
1069 public TypeSpec GetArgumentType ()
1071 TypeOf e = GetValue () as TypeOf;
1074 return e.TypeArgument;
1077 public override Expression CreateExpressionTree (ResolveContext ec)
1079 throw new NotSupportedException ("ET");
1082 protected override Expression DoResolve (ResolveContext ec)
1084 throw new NotImplementedException ();
1087 public override void Emit (EmitContext ec)
1089 throw new NotImplementedException ();
1095 /// For global attributes (assembly, module) we need special handling.
1096 /// Attributes can be located in the several files
1098 public class GlobalAttribute : Attribute
1100 public readonly NamespaceEntry ns;
1102 public GlobalAttribute (NamespaceEntry ns, string target, ATypeNameExpression expression,
1103 Arguments[] args, Location loc, bool nameEscaped):
1104 base (target, expression, args, loc, nameEscaped)
1111 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1112 // each time a new file is parsed. However, we need to use the NamespaceEntry
1113 // in effect where the attribute was used. Since code elsewhere cannot assume
1114 // that the NamespaceEntry is right, just overwrite it.
1116 // Precondition: RootContext.ToplevelTypes == null
1118 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1119 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1121 RootContext.ToplevelTypes.NamespaceEntry = ns;
1124 protected override bool IsSecurityActionValid (bool for_assembly)
1126 return base.IsSecurityActionValid (true);
1131 RootContext.ToplevelTypes.NamespaceEntry = null;
1134 protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
1138 return base.ResolveAsTypeTerminal (expr, ec);
1145 protected override MethodSpec ResolveConstructor (ResolveContext ec)
1149 return base.ResolveConstructor (ec);
1156 protected override bool ResolveNamedArguments (ResolveContext ec)
1160 return base.ResolveNamedArguments (ec);
1168 public class Attributes {
1169 public readonly List<Attribute> Attrs;
1171 public Attributes (Attribute a)
1173 Attrs = new List<Attribute> ();
1177 public Attributes (List<Attribute> attrs)
1182 public void AddAttributes (List<Attribute> attrs)
1184 Attrs.AddRange (attrs);
1187 public void AttachTo (Attributable attributable, IMemberContext context)
1189 foreach (Attribute a in Attrs)
1190 a.AttachTo (attributable, context);
1193 public Attributes Clone ()
1195 var al = new List<Attribute> (Attrs.Count);
1196 foreach (Attribute a in Attrs)
1197 al.Add (a.Clone ());
1199 return new Attributes (al);
1203 /// Checks whether attribute target is valid for the current element
1205 public bool CheckTargets ()
1207 foreach (Attribute a in Attrs) {
1208 if (!a.CheckTarget ())
1214 public Attribute Search (PredefinedAttribute t)
1216 return Search (null, t);
1219 public Attribute Search (string explicitTarget, PredefinedAttribute t)
1221 foreach (Attribute a in Attrs) {
1222 if (explicitTarget != null && a.ExplicitTarget != explicitTarget)
1225 if (a.ResolveType () == t)
1232 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1234 public Attribute[] SearchMulti (PredefinedAttribute t)
1236 List<Attribute> ar = null;
1238 foreach (Attribute a in Attrs) {
1239 if (a.ResolveType () == t) {
1241 ar = new List<Attribute> (Attrs.Count);
1246 return ar == null ? null : ar.ToArray ();
1253 Dictionary<Attribute, List<Attribute>> ld = Attrs.Count > 1 ? new Dictionary<Attribute, List<Attribute>> () : null;
1255 foreach (Attribute a in Attrs)
1258 if (ld == null || ld.Count == 0)
1261 foreach (var d in ld) {
1262 if (d.Value == null)
1265 Attribute a = d.Key;
1267 foreach (Attribute collision in d.Value)
1268 a.Report.SymbolRelatedToPreviousError (collision.Location, "");
1270 a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
1271 a.GetSignatureForError ());
1275 public bool Contains (PredefinedAttribute t)
1277 return Search (t) != null;
1281 public sealed class AttributeEncoder
1284 public enum EncodedTypeProperties
1288 TypeParameter = 1 << 1
1291 public static readonly byte[] Empty;
1295 const ushort Version = 1;
1297 static AttributeEncoder ()
1299 Empty = new byte[4];
1300 Empty[0] = (byte) Version;
1303 public AttributeEncoder ()
1305 buffer = new byte[32];
1309 public void Encode (bool value)
1311 Encode (value ? (byte) 1 : (byte) 0);
1314 public void Encode (byte value)
1316 if (pos == buffer.Length)
1319 buffer [pos++] = value;
1322 public void Encode (sbyte value)
1324 Encode ((byte) value);
1327 public void Encode (short value)
1329 if (pos + 2 > buffer.Length)
1332 buffer[pos++] = (byte) value;
1333 buffer[pos++] = (byte) (value >> 8);
1336 public void Encode (ushort value)
1338 Encode ((short) value);
1341 public void Encode (int value)
1343 if (pos + 4 > buffer.Length)
1346 buffer[pos++] = (byte) value;
1347 buffer[pos++] = (byte) (value >> 8);
1348 buffer[pos++] = (byte) (value >> 16);
1349 buffer[pos++] = (byte) (value >> 24);
1352 public void Encode (uint value)
1354 Encode ((int) value);
1357 public void Encode (long value)
1359 if (pos + 8 > buffer.Length)
1362 buffer[pos++] = (byte) value;
1363 buffer[pos++] = (byte) (value >> 8);
1364 buffer[pos++] = (byte) (value >> 16);
1365 buffer[pos++] = (byte) (value >> 24);
1366 buffer[pos++] = (byte) (value >> 32);
1367 buffer[pos++] = (byte) (value >> 40);
1368 buffer[pos++] = (byte) (value >> 48);
1369 buffer[pos++] = (byte) (value >> 56);
1372 public void Encode (ulong value)
1374 Encode ((long) value);
1377 public void Encode (float value)
1379 Encode (SingleConverter.SingleToInt32Bits (value));
1382 public void Encode (double value)
1384 Encode (BitConverter.DoubleToInt64Bits (value));
1387 public void Encode (string value)
1389 if (value == null) {
1390 Encode ((byte) 0xFF);
1394 var buf = Encoding.UTF8.GetBytes(value);
1395 WriteCompressedValue (buf.Length);
1397 if (pos + buf.Length > buffer.Length)
1400 Buffer.BlockCopy (buf, 0, buffer, pos, buf.Length);
1404 public EncodedTypeProperties Encode (TypeSpec type)
1406 switch (type.BuildinType) {
1407 case BuildinTypeSpec.Type.Bool:
1408 Encode ((byte) 0x02);
1410 case BuildinTypeSpec.Type.Char:
1411 Encode ((byte) 0x03);
1413 case BuildinTypeSpec.Type.SByte:
1414 Encode ((byte) 0x04);
1416 case BuildinTypeSpec.Type.Byte:
1417 Encode ((byte) 0x05);
1419 case BuildinTypeSpec.Type.Short:
1420 Encode ((byte) 0x06);
1422 case BuildinTypeSpec.Type.UShort:
1423 Encode ((byte) 0x07);
1425 case BuildinTypeSpec.Type.Int:
1426 Encode ((byte) 0x08);
1428 case BuildinTypeSpec.Type.UInt:
1429 Encode ((byte) 0x09);
1431 case BuildinTypeSpec.Type.Long:
1432 Encode ((byte) 0x0A);
1434 case BuildinTypeSpec.Type.ULong:
1435 Encode ((byte) 0x0B);
1437 case BuildinTypeSpec.Type.Float:
1438 Encode ((byte) 0x0C);
1440 case BuildinTypeSpec.Type.Double:
1441 Encode ((byte) 0x0D);
1443 case BuildinTypeSpec.Type.String:
1444 Encode ((byte) 0x0E);
1446 case BuildinTypeSpec.Type.Type:
1447 Encode ((byte) 0x50);
1449 case BuildinTypeSpec.Type.Object:
1450 Encode ((byte) 0x51);
1452 case BuildinTypeSpec.Type.Dynamic:
1453 Encode ((byte) 0x51);
1454 return EncodedTypeProperties.DynamicType;
1457 Encode ((byte) 0x1D);
1458 return Encode (TypeManager.GetElementType (type));
1461 if (type.Kind == MemberKind.Enum) {
1462 Encode ((byte) 0x55);
1463 EncodeTypeName (type);
1469 return EncodedTypeProperties.None;
1472 public void EncodeTypeName (TypeSpec type)
1474 var old_type = type.GetMetaInfo ();
1475 Encode (type.MemberDefinition.IsImported ? old_type.AssemblyQualifiedName : old_type.FullName);
1479 // Encodes single property named argument per call
1481 public void EncodeNamedPropertyArgument (PropertySpec property, Constant value)
1483 Encode ((ushort) 1); // length
1484 Encode ((byte) 0x54); // property
1485 Encode (property.MemberType);
1486 Encode (property.Name);
1487 value.EncodeAttributeValue (null, this, property.MemberType);
1491 // Encodes single field named argument per call
1493 public void EncodeNamedFieldArgument (FieldSpec field, Constant value)
1495 Encode ((ushort) 1); // length
1496 Encode ((byte) 0x53); // field
1497 Encode (field.MemberType);
1498 Encode (field.Name);
1499 value.EncodeAttributeValue (null, this, field.MemberType);
1502 public void EncodeNamedArguments<T> (T[] members, Constant[] values) where T : MemberSpec, IInterfaceMemberSpec
1504 Encode ((ushort) members.Length);
1506 for (int i = 0; i < members.Length; ++i)
1508 var member = members[i];
1510 if (member.Kind == MemberKind.Field)
1511 Encode ((byte) 0x53);
1512 else if (member.Kind == MemberKind.Property)
1513 Encode ((byte) 0x54);
1515 throw new NotImplementedException (member.Kind.ToString ());
1517 Encode (member.MemberType);
1518 Encode (member.Name);
1519 values [i].EncodeAttributeValue (null, this, member.MemberType);
1523 public void EncodeEmptyNamedArguments ()
1525 Encode ((ushort) 0);
1530 int size = System.Math.Max (pos * 4, pos + inc + 2);
1531 Array.Resize (ref buffer, size);
1534 void WriteCompressedValue (int value)
1537 Encode ((byte) value);
1541 if (value < 0x4000) {
1542 Encode ((byte) (0x80 | (value >> 8)));
1543 Encode ((byte) value);
1550 public byte[] ToArray ()
1552 byte[] buf = new byte[pos];
1553 Array.Copy (buffer, buf, pos);
1560 /// Helper class for attribute verification routine.
1562 static class AttributeTester
1564 public enum Result {
1571 /// Returns true if parameters of two compared methods are CLS-Compliant.
1572 /// It tests differing only in ref or out, or in array rank.
1574 public static Result AreOverloadedMethodParamsClsCompliant (AParametersCollection pa, AParametersCollection pb)
1576 TypeSpec [] types_a = pa.Types;
1577 TypeSpec [] types_b = pb.Types;
1578 if (types_a == null || types_b == null)
1581 if (types_a.Length != types_b.Length)
1584 Result result = Result.Ok;
1585 for (int i = 0; i < types_b.Length; ++i) {
1586 TypeSpec aType = types_a [i];
1587 TypeSpec bType = types_b [i];
1589 var ac_a = aType as ArrayContainer;
1590 var ac_b = aType as ArrayContainer;
1592 if (ac_a != null && ac_b != null) {
1593 if (ac_a.Rank != ac_b.Rank && ac_a.Element == ac_b.Element) {
1594 result = Result.RefOutArrayError;
1598 if (ac_a.Element.IsArray || ac_b.Element.IsArray) {
1599 result = Result.ArrayArrayError;
1607 const Parameter.Modifier out_ref_mod = (Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
1608 if ((pa.FixedParameters[i].ModFlags & out_ref_mod) != (pb.FixedParameters[i].ModFlags & out_ref_mod))
1609 result = Result.RefOutArrayError;
1615 /// Common method for Obsolete error/warning reporting.
1617 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report)
1620 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1624 if (oa.Message == null || oa.Message.Length == 0) {
1625 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1628 Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1633 // Predefined attribute types
1635 public class PredefinedAttributes
1637 // Build-in attributes
1638 public readonly PredefinedAttribute ParamArray;
1639 public readonly PredefinedAttribute Out;
1641 // Optional attributes
1642 public readonly PredefinedAttribute Obsolete;
1643 public readonly PredefinedAttribute DllImport;
1644 public readonly PredefinedAttribute MethodImpl;
1645 public readonly PredefinedAttribute MarshalAs;
1646 public readonly PredefinedAttribute In;
1647 public readonly PredefinedAttribute IndexerName;
1648 public readonly PredefinedAttribute Conditional;
1649 public readonly PredefinedAttribute CLSCompliant;
1650 public readonly PredefinedAttribute Security;
1651 public readonly PredefinedAttribute Required;
1652 public readonly PredefinedAttribute Guid;
1653 public readonly PredefinedAttribute AssemblyCulture;
1654 public readonly PredefinedAttribute AssemblyVersion;
1655 public readonly PredefinedAttribute AssemblyAlgorithmId;
1656 public readonly PredefinedAttribute AssemblyFlags;
1657 public readonly PredefinedAttribute AssemblyFileVersion;
1658 public readonly PredefinedAttribute ComImport;
1659 public readonly PredefinedAttribute CoClass;
1660 public readonly PredefinedAttribute AttributeUsage;
1661 public readonly PredefinedAttribute DefaultParameterValue;
1662 public readonly PredefinedAttribute OptionalParameter;
1663 public readonly PredefinedAttribute UnverifiableCode;
1666 public readonly PredefinedAttribute DefaultCharset;
1667 public readonly PredefinedAttribute TypeForwarder;
1668 public readonly PredefinedAttribute FixedBuffer;
1669 public readonly PredefinedAttribute CompilerGenerated;
1670 public readonly PredefinedAttribute InternalsVisibleTo;
1671 public readonly PredefinedAttribute RuntimeCompatibility;
1672 public readonly PredefinedAttribute DebuggerHidden;
1673 public readonly PredefinedAttribute UnsafeValueType;
1676 public readonly PredefinedAttribute Extension;
1679 public readonly PredefinedDynamicAttribute Dynamic;
1682 // Optional types which are used as types and for member lookup
1684 public readonly PredefinedAttribute DefaultMember;
1685 public readonly PredefinedDecimalAttribute DecimalConstant;
1686 public readonly PredefinedAttribute StructLayout;
1687 public readonly PredefinedAttribute FieldOffset;
1689 public PredefinedAttributes (ModuleContainer module)
1691 ParamArray = new PredefinedAttribute (module, "System", "ParamArrayAttribute");
1692 Out = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OutAttribute");
1693 ParamArray.Resolve (Location.Null);
1694 Out.Resolve (Location.Null);
1696 Obsolete = new PredefinedAttribute (module, "System", "ObsoleteAttribute");
1697 DllImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DllImportAttribute");
1698 MethodImpl = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "MethodImplAttribute");
1699 MarshalAs = new PredefinedAttribute (module, "System.Runtime.InteropServices", "MarshalAsAttribute");
1700 In = new PredefinedAttribute (module, "System.Runtime.InteropServices", "InAttribute");
1701 IndexerName = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IndexerNameAttribute");
1702 Conditional = new PredefinedAttribute (module, "System.Diagnostics", "ConditionalAttribute");
1703 CLSCompliant = new PredefinedAttribute (module, "System", "CLSCompliantAttribute");
1704 Security = new PredefinedAttribute (module, "System.Security.Permissions", "SecurityAttribute");
1705 Required = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1706 Guid = new PredefinedAttribute (module, "System.Runtime.InteropServices", "GuidAttribute");
1707 AssemblyCulture = new PredefinedAttribute (module, "System.Reflection", "AssemblyCultureAttribute");
1708 AssemblyVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyVersionAttribute");
1709 AssemblyAlgorithmId = new PredefinedAttribute (module, "System.Reflection", "AssemblyAlgorithmIdAttribute");
1710 AssemblyFlags = new PredefinedAttribute (module, "System.Reflection", "AssemblyFlagsAttribute");
1711 AssemblyFileVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyFileVersionAttribute");
1712 ComImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "ComImportAttribute");
1713 CoClass = new PredefinedAttribute (module, "System.Runtime.InteropServices", "CoClassAttribute");
1714 AttributeUsage = new PredefinedAttribute (module, "System", "AttributeUsageAttribute");
1715 DefaultParameterValue = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1716 OptionalParameter = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OptionalAttribute");
1717 UnverifiableCode = new PredefinedAttribute (module, "System.Security", "UnverifiableCodeAttribute");
1719 DefaultCharset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
1720 TypeForwarder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1721 FixedBuffer = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "FixedBufferAttribute");
1722 CompilerGenerated = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1723 InternalsVisibleTo = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1724 RuntimeCompatibility = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1725 DebuggerHidden = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerHiddenAttribute");
1726 UnsafeValueType = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1728 Extension = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "ExtensionAttribute");
1730 Dynamic = new PredefinedDynamicAttribute (module, "System.Runtime.CompilerServices", "DynamicAttribute");
1732 DefaultMember = new PredefinedAttribute (module, "System.Reflection", "DefaultMemberAttribute");
1733 DecimalConstant = new PredefinedDecimalAttribute (module, "System.Runtime.CompilerServices", "DecimalConstantAttribute");
1734 StructLayout = new PredefinedAttribute (module, "System.Runtime.InteropServices", "StructLayoutAttribute");
1735 FieldOffset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "FieldOffsetAttribute");
1737 // TODO: Should define only attributes which are used for comparison
1738 const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
1739 System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly;
1741 foreach (var fi in GetType ().GetFields (all_fields)) {
1742 ((PredefinedAttribute) fi.GetValue (this)).Define ();
1747 public class PredefinedAttribute : PredefinedType
1749 protected MethodSpec ctor;
1750 List<PropertySpec> properties;
1752 public PredefinedAttribute (ModuleContainer module, string ns, string name)
1753 : base (module, MemberKind.Class, ns, name)
1759 public MethodSpec Constructor {
1767 public static bool operator == (TypeSpec type, PredefinedAttribute pa)
1769 return type == pa.type && pa.type != null;
1772 public static bool operator != (TypeSpec type, PredefinedAttribute pa)
1774 return type != pa.type;
1777 public override int GetHashCode ()
1779 return base.GetHashCode ();
1782 public override bool Equals (object obj)
1784 throw new NotSupportedException ();
1787 public void EmitAttribute (ConstructorBuilder builder)
1789 if (ResolveBuilder ())
1790 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1793 public void EmitAttribute (MethodBuilder builder)
1795 if (ResolveBuilder ())
1796 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1799 public void EmitAttribute (PropertyBuilder builder)
1801 if (ResolveBuilder ())
1802 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1805 public void EmitAttribute (FieldBuilder builder)
1807 if (ResolveBuilder ())
1808 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1811 public void EmitAttribute (FieldBuilder builder, AttributeEncoder argsEncoded)
1813 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1816 public void EmitAttribute (TypeBuilder builder)
1818 if (ResolveBuilder ())
1819 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1822 public void EmitAttribute (TypeBuilder builder, AttributeEncoder argsEncoded)
1824 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1827 public void EmitAttribute (AssemblyBuilder builder)
1829 if (ResolveBuilder ())
1830 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1833 public void EmitAttribute (ModuleBuilder builder)
1835 if (ResolveBuilder ())
1836 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1839 public void EmitAttribute (ParameterBuilder builder)
1841 if (ResolveBuilder ())
1842 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1845 public void EmitAttribute (ParameterBuilder builder, AttributeEncoder argsEncoded)
1847 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1850 ConstructorInfo GetCtorMetaInfo ()
1852 return (ConstructorInfo) ctor.GetMetaInfo ();
1855 public PropertySpec GetProperty (string name, TypeSpec memberType, Location loc)
1859 if (properties != null) {
1860 spec = properties.Find (l => l.Name == name);
1866 spec = TypeManager.GetPredefinedProperty (type, name, loc, memberType);
1869 if (properties == null) {
1870 properties = new List<PropertySpec> ();
1873 properties.Add (spec);
1880 public bool ResolveBuilder ()
1886 // Handle all parameter-less attributes as optional
1891 ctor = TypeManager.GetPredefinedConstructor (type, Location.Null, TypeSpec.EmptyTypes);
1892 return ctor != null;
1895 public bool ResolveConstructor (Location loc, params TypeSpec[] argType)
1898 throw new InternalErrorException ("Predefined ctor redefined");
1900 if (Resolve (loc) == null)
1903 ctor = TypeManager.GetPredefinedConstructor (type, loc, argType);
1904 return ctor != null;
1908 public class PredefinedDecimalAttribute : PredefinedAttribute
1910 public PredefinedDecimalAttribute (ModuleContainer module, string ns, string name)
1911 : base (module, ns, name)
1915 public void EmitAttribute (ParameterBuilder builder, decimal value, Location loc)
1917 if (Resolve (loc) == null)
1920 if (ctor == null && !ResolveConstructor (loc, module.Compiler.BuildinTypes.Byte, module.Compiler.BuildinTypes.Byte,
1921 module.Compiler.BuildinTypes.UInt, module.Compiler.BuildinTypes.UInt, module.Compiler.BuildinTypes.UInt))
1924 int[] bits = decimal.GetBits (value);
1925 AttributeEncoder encoder = new AttributeEncoder ();
1926 encoder.Encode ((byte) (bits[3] >> 16));
1927 encoder.Encode ((byte) (bits[3] >> 31));
1928 encoder.Encode ((uint) bits[2]);
1929 encoder.Encode ((uint) bits[1]);
1930 encoder.Encode ((uint) bits[0]);
1931 encoder.EncodeEmptyNamedArguments ();
1933 EmitAttribute (builder, encoder);
1936 public void EmitAttribute (FieldBuilder builder, decimal value, Location loc)
1938 if (Resolve (loc) == null)
1941 if (ctor == null && !ResolveConstructor (loc, module.Compiler.BuildinTypes.Byte, module.Compiler.BuildinTypes.Byte,
1942 module.Compiler.BuildinTypes.UInt, module.Compiler.BuildinTypes.UInt, module.Compiler.BuildinTypes.UInt))
1945 int[] bits = decimal.GetBits (value);
1946 AttributeEncoder encoder = new AttributeEncoder ();
1947 encoder.Encode ((byte) (bits[3] >> 16));
1948 encoder.Encode ((byte) (bits[3] >> 31));
1949 encoder.Encode ((uint) bits[2]);
1950 encoder.Encode ((uint) bits[1]);
1951 encoder.Encode ((uint) bits[0]);
1952 encoder.EncodeEmptyNamedArguments ();
1954 EmitAttribute (builder, encoder);
1958 public class PredefinedDynamicAttribute : PredefinedAttribute
1962 public PredefinedDynamicAttribute (ModuleContainer module, string ns, string name)
1963 : base (module, ns, name)
1967 public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
1969 if (ResolveTransformationCtor (loc)) {
1970 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1971 builder.SetCustomAttribute (cab);
1975 public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
1977 if (ResolveTransformationCtor (loc)) {
1978 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1979 builder.SetCustomAttribute (cab);
1983 public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
1985 if (ResolveTransformationCtor (loc)) {
1986 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1987 builder.SetCustomAttribute (cab);
1991 public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
1993 if (ResolveTransformationCtor (loc)) {
1994 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1995 builder.SetCustomAttribute (cab);
2000 // When any element of the type is a dynamic type
2002 // This method builds a transformation array for dynamic types
2003 // used in places where DynamicAttribute cannot be applied to.
2004 // It uses bool flag when type is of dynamic type and each
2005 // section always starts with "false" for some reason.
2007 // LAMESPEC: This should be part of C# specification
2009 // Example: Func<dynamic, int, dynamic[]>
2010 // Transformation: { false, true, false, false, true }
2012 static bool[] GetTransformationFlags (TypeSpec t)
2015 var ac = t as ArrayContainer;
2017 element = GetTransformationFlags (ac.Element);
2018 if (element == null)
2021 bool[] res = new bool[element.Length + 1];
2023 Array.Copy (element, 0, res, 1, element.Length);
2031 List<bool> transform = null;
2032 var targs = t.TypeArguments;
2033 for (int i = 0; i < targs.Length; ++i) {
2034 element = GetTransformationFlags (targs[i]);
2035 if (element != null) {
2036 if (transform == null) {
2037 transform = new List<bool> ();
2038 for (int ii = 0; ii <= i; ++ii)
2039 transform.Add (false);
2042 transform.AddRange (element);
2043 } else if (transform != null) {
2044 transform.Add (false);
2048 if (transform != null)
2049 return transform.ToArray ();
2052 if (t.BuildinType == BuildinTypeSpec.Type.Dynamic)
2053 return new bool[] { true };
2058 bool ResolveTransformationCtor (Location loc)
2063 if (Resolve (loc) == null)
2066 tctor = TypeManager.GetPredefinedConstructor (type, Location.Null, ArrayContainer.MakeType (module, module.Compiler.BuildinTypes.Bool));
2067 return tctor != null;