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, 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 static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name)
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",
202 static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name)
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",
209 public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc)
211 context.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression");
214 public void Error_MissingGuidAttribute ()
216 Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
219 public void Error_MisusedExtensionAttribute ()
221 Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
224 public void Error_MisusedDynamicAttribute ()
226 Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
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.
233 public void Error_AttributeEmitError (string inner)
235 Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
236 TypeManager.CSharpName (Type), inner);
239 public void Error_InvalidSecurityParent ()
241 Error_AttributeEmitError ("it is attached to invalid parent");
250 protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
252 return expr.ResolveAsTypeTerminal (ec, false);
255 TypeSpec ResolvePossibleAttributeType (ATypeNameExpression expr, ref bool is_attr)
257 TypeExpr te = ResolveAsTypeTerminal (expr, context);
261 TypeSpec t = te.Type;
265 Report.SymbolRelatedToPreviousError (t);
266 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
272 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
274 void ResolveAttributeType ()
276 SessionReportPrinter resolve_printer = new SessionReportPrinter ();
277 ReportPrinter prev_recorder = context.Compiler.Report.SetPrinter (resolve_printer);
279 bool t1_is_attr = false;
280 bool t2_is_attr = false;
282 ATypeNameExpression expanded = null;
285 t1 = ResolvePossibleAttributeType (expression, ref t1_is_attr);
290 expanded = (ATypeNameExpression) expression.Clone (null);
291 expanded.Name += "Attribute";
293 t2 = ResolvePossibleAttributeType (expanded, ref t2_is_attr);
296 resolve_printer.EndSession ();
298 context.Compiler.Report.SetPrinter (prev_recorder);
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;
318 resolve_printer.Merge (prev_recorder);
319 resolve_error = true;
322 public virtual TypeSpec ResolveType ()
324 if (Type == null && !resolve_error)
325 ResolveAttributeType ();
329 public override string GetSignatureForError ()
332 return TypeManager.CSharpName (Type);
334 return expression.GetSignatureForError ();
337 public bool HasSecurityAttribute {
339 PredefinedAttribute pa = context.Module.PredefinedAttributes.Security;
340 return pa.IsDefined && TypeSpec.IsBaseClass (type, pa.TypeSpec, false);
344 public bool IsValidSecurityAttribute ()
346 return HasSecurityAttribute && IsSecurityActionValid (false);
349 static bool IsValidArgumentType (TypeSpec t)
352 t = TypeManager.GetElementType (t);
354 return t == TypeManager.string_type ||
355 TypeManager.IsPrimitiveType (t) ||
356 TypeManager.IsEnumType (t) ||
357 t == TypeManager.object_type ||
358 t == TypeManager.type_type;
361 // TODO: Don't use this ambiguous value
363 get { return expression.Name; }
366 public Report Report {
367 get { return context.Compiler.Report; }
370 public MethodSpec Resolve ()
375 resolve_error = true;
379 ResolveAttributeType ();
384 if (Type.IsAbstract) {
385 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
389 ObsoleteAttribute obsolete_attr = Type.GetAttributeObsolete ();
390 if (obsolete_attr != null) {
391 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location, Report);
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;
403 ResolveContext rc = new ResolveContext (context, ResolveContext.Options.ConstantScope);
404 ctor = ResolveConstructor (rc);
410 // Add [module: DefaultCharSet] to all DllImport import attributes
412 var module = context.Module;
413 // HACK: Needed for broken ModuleContainer::ResolveGlobalAttributes
414 if (module.PredefinedAttributes == null)
417 if (Type == module.PredefinedAttributes.DllImport && module.HasDefaultCharSet) {
418 AddModuleCharSet (rc);
421 if (NamedArguments != null && !ResolveNamedArguments (rc)) {
425 resolve_error = false;
429 protected virtual MethodSpec ResolveConstructor (ResolveContext ec)
431 if (PosArguments != null) {
433 PosArguments.Resolve (ec, out dynamic);
435 Error_AttributeArgumentIsDynamic (ec.MemberContext, loc);
440 return ConstructorLookup (ec, Type, ref PosArguments, loc);
443 protected virtual bool ResolveNamedArguments (ResolveContext ec)
445 int named_arg_count = NamedArguments.Count;
446 var seen_names = new List<string> (named_arg_count);
448 named_values = new List<KeyValuePair<MemberExpr, NamedArgument>> (named_arg_count);
450 foreach (NamedArgument a in NamedArguments) {
451 string name = a.Name;
452 if (seen_names.Contains (name)) {
453 ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name);
457 seen_names.Add (name);
461 Expression member = Expression.MemberLookup (ec, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
463 if (member == null) {
464 member = Expression.MemberLookup (null, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
466 if (member != null) {
467 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
468 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
474 Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name);
478 if (!(member is PropertyExpr || member is FieldExpr)) {
479 Error_InvalidNamedArgument (ec, a);
483 ObsoleteAttribute obsolete_attr;
485 if (member is PropertyExpr) {
486 var pi = ((PropertyExpr) member).PropertyInfo;
488 if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) {
489 ec.Report.SymbolRelatedToPreviousError (pi);
490 Error_InvalidNamedArgument (ec, a);
494 if (!IsValidArgumentType (member.Type)) {
495 ec.Report.SymbolRelatedToPreviousError (pi);
496 Error_InvalidNamedArgumentType (ec, a);
500 obsolete_attr = pi.GetAttributeObsolete ();
501 pi.MemberDefinition.SetIsAssigned ();
503 var fi = ((FieldExpr) member).Spec;
505 if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) {
506 Error_InvalidNamedArgument (ec, a);
510 if (!IsValidArgumentType (member.Type)) {
511 ec.Report.SymbolRelatedToPreviousError (fi);
512 Error_InvalidNamedArgumentType (ec, a);
516 obsolete_attr = fi.GetAttributeObsolete ();
517 fi.MemberDefinition.SetIsAssigned ();
520 if (obsolete_attr != null && !context.IsObsolete)
521 AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location, Report);
523 if (a.Type != member.Type) {
524 a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location);
528 named_values.Add (new KeyValuePair<MemberExpr, NamedArgument> ((MemberExpr) member, a));
535 /// Get a string containing a list of valid targets for the attribute 'attr'
537 public string GetValidTargets ()
539 StringBuilder sb = new StringBuilder ();
540 AttributeTargets targets = Type.GetAttributeUsage (context.Module.PredefinedAttributes.AttributeUsage).ValidOn;
542 if ((targets & AttributeTargets.Assembly) != 0)
543 sb.Append ("assembly, ");
545 if ((targets & AttributeTargets.Module) != 0)
546 sb.Append ("module, ");
548 if ((targets & AttributeTargets.Class) != 0)
549 sb.Append ("class, ");
551 if ((targets & AttributeTargets.Struct) != 0)
552 sb.Append ("struct, ");
554 if ((targets & AttributeTargets.Enum) != 0)
555 sb.Append ("enum, ");
557 if ((targets & AttributeTargets.Constructor) != 0)
558 sb.Append ("constructor, ");
560 if ((targets & AttributeTargets.Method) != 0)
561 sb.Append ("method, ");
563 if ((targets & AttributeTargets.Property) != 0)
564 sb.Append ("property, indexer, ");
566 if ((targets & AttributeTargets.Field) != 0)
567 sb.Append ("field, ");
569 if ((targets & AttributeTargets.Event) != 0)
570 sb.Append ("event, ");
572 if ((targets & AttributeTargets.Interface) != 0)
573 sb.Append ("interface, ");
575 if ((targets & AttributeTargets.Parameter) != 0)
576 sb.Append ("parameter, ");
578 if ((targets & AttributeTargets.Delegate) != 0)
579 sb.Append ("delegate, ");
581 if ((targets & AttributeTargets.ReturnValue) != 0)
582 sb.Append ("return, ");
584 if ((targets & AttributeTargets.GenericParameter) != 0)
585 sb.Append ("type parameter, ");
587 return sb.Remove (sb.Length - 2, 2).ToString ();
590 public AttributeUsageAttribute GetAttributeUsageAttribute ()
593 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
594 // But because a lot of attribute class code must be rewritten will be better to wait...
598 return DefaultUsageAttribute;
600 AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)((Constant) PosArguments [0].Expr).GetValue ());
602 var field = GetNamedValue ("AllowMultiple") as BoolConstant;
604 usage_attribute.AllowMultiple = field.Value;
606 field = GetNamedValue ("Inherited") as BoolConstant;
608 usage_attribute.Inherited = field.Value;
610 return usage_attribute;
614 /// Returns custom name of indexer
616 public string GetIndexerAttributeValue ()
619 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
620 // But because a lot of attribute class code must be rewritten will be better to wait...
626 return ((Constant) PosArguments [0].Expr).GetValue () as string;
630 /// Returns condition of ConditionalAttribute
632 public string GetConditionalAttributeValue ()
635 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
636 // But because a lot of attribute class code must be rewritten will be better to wait...
642 return ((Constant) PosArguments[0].Expr).GetValue () as string;
646 /// Creates the instance of ObsoleteAttribute from this attribute instance
648 public ObsoleteAttribute GetObsoleteAttribute ()
651 // corlib only case when obsolete is used before is resolved
652 var c = type.MemberDefinition as Class;
653 if (c != null && !c.HasMembersDefined)
656 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
657 // But because a lot of attribute class code must be rewritten will be better to wait...
664 if (PosArguments == null)
665 return new ObsoleteAttribute ();
667 string msg = ((Constant) PosArguments[0].Expr).GetValue () as string;
668 if (PosArguments.Count == 1)
669 return new ObsoleteAttribute (msg);
671 return new ObsoleteAttribute (msg, ((BoolConstant) PosArguments[1].Expr).Value);
675 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
676 /// before ApplyAttribute. We need to resolve the arguments.
677 /// This situation occurs when class deps is differs from Emit order.
679 public bool GetClsCompliantAttributeValue ()
682 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
683 // But because a lot of attribute class code must be rewritten will be better to wait...
689 return ((BoolConstant) PosArguments[0].Expr).Value;
692 public TypeSpec GetCoClassAttributeValue ()
700 return GetArgumentType ();
703 public bool CheckTarget ()
705 string[] valid_targets = Owner.ValidAttributeTargets;
706 if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
707 Target = Owner.AttributeTargets;
711 // TODO: we can skip the first item
712 if (Array.Exists (valid_targets, i => i == ExplicitTarget)) {
713 switch (ExplicitTarget) {
714 case "return": Target = AttributeTargets.ReturnValue; return true;
715 case "param": Target = AttributeTargets.Parameter; return true;
716 case "field": Target = AttributeTargets.Field; return true;
717 case "method": Target = AttributeTargets.Method; return true;
718 case "property": Target = AttributeTargets.Property; return true;
719 case "module": Target = AttributeTargets.Module; return true;
721 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
724 StringBuilder sb = new StringBuilder ();
725 foreach (string s in valid_targets) {
729 sb.Remove (sb.Length - 2, 2);
730 Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
731 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
736 /// Tests permitted SecurityAction for assembly or other types
738 protected virtual bool IsSecurityActionValid (bool for_assembly)
740 SecurityAction action = GetSecurityActionValue ();
743 #pragma warning disable 618
744 case SecurityAction.Demand:
745 case SecurityAction.Assert:
746 case SecurityAction.Deny:
747 case SecurityAction.PermitOnly:
748 case SecurityAction.LinkDemand:
749 case SecurityAction.InheritanceDemand:
754 case SecurityAction.RequestMinimum:
755 case SecurityAction.RequestOptional:
756 case SecurityAction.RequestRefuse:
760 #pragma warning restore 618
763 Error_AttributeEmitError ("SecurityAction is out of range");
767 Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
771 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
773 return (SecurityAction) ((Constant) PosArguments[0].Expr).GetValue ();
777 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
779 /// <returns></returns>
780 public void ExtractSecurityPermissionSet (MethodSpec ctor, ref SecurityType permissions)
783 object[] values = new object [PosArguments.Count];
784 for (int i = 0; i < values.Length; ++i)
785 values [i] = ((Constant) PosArguments [i].Expr).GetValue ();
788 object[] prop_values;
789 if (named_values == null) {
793 prop = new PropertyInfo[named_values.Count];
794 prop_values = new object [named_values.Count];
795 for (int i = 0; i < prop.Length; ++i) {
796 prop [i] = ((PropertyExpr) named_values [i].Key).PropertyInfo.MetaInfo;
797 prop_values [i] = ((Constant) named_values [i].Value.Expr).GetValue ();
801 if (permissions == null)
802 permissions = new SecurityType ();
804 var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), values, prop, prop_values);
805 permissions.Add (cab);
807 Type orig_assembly_type = null;
809 if (Type.MemberDefinition is TypeContainer) {
810 if (!RootContext.StdLib) {
811 orig_assembly_type = System.Type.GetType (Type.GetMetaInfo ().FullName);
813 string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
814 if (orig_version_path == null) {
815 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
819 if (orig_sec_assembly == null) {
820 string file = Path.Combine (orig_version_path, Path.GetFileName (RootContext.OutputFile));
821 orig_sec_assembly = Assembly.LoadFile (file);
824 orig_assembly_type = orig_sec_assembly.GetType (Type.GetMetaInfo ().FullName, true);
825 if (orig_assembly_type == null) {
826 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' " +
827 "was not found in previous version of assembly");
833 SecurityAttribute sa;
836 // For all non-selfreferencing security attributes we can avoid all hacks
837 if (orig_assembly_type == null) {
838 args = new object[PosArguments.Count];
839 for (int j = 0; j < args.Length; ++j) {
840 args[j] = ((Constant) PosArguments[j].Expr).GetValue ();
843 sa = (SecurityAttribute) Activator.CreateInstance (Type.GetMetaInfo (), args);
845 if (named_values != null) {
846 for (int i = 0; i < named_values.Count; ++i) {
847 PropertyInfo pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
848 pi.SetValue (sa, ((Constant) named_values [i].Value.Expr).GetValue (), null);
852 // HACK: All security attributes have same ctor syntax
853 args = new object[] { GetSecurityActionValue () };
854 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, args);
856 // All types are from newly created assembly but for invocation with old one we need to convert them
857 if (named_values != null) {
858 for (int i = 0; i < named_values.Count; ++i) {
859 PropertyInfo emited_pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
860 // FIXME: We are missing return type filter
861 // TODO: pi can be null
862 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name);
864 pi.SetValue (sa, ((Constant) named_values[i].Value.Expr).GetValue (), null);
870 perm = sa.CreatePermission ();
871 SecurityAction action = (SecurityAction) args [0];
873 // IS is correct because for corlib we are using an instance from old corlib
874 if (!(perm is System.Security.CodeAccessPermission)) {
876 case SecurityAction.Demand:
877 action = (SecurityAction)13;
879 case SecurityAction.LinkDemand:
880 action = (SecurityAction)14;
882 case SecurityAction.InheritanceDemand:
883 action = (SecurityAction)15;
888 if (permissions == null)
889 permissions = new SecurityType ();
892 if (!permissions.TryGetValue (action, out ps)) {
893 if (sa is PermissionSetAttribute)
894 ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
896 ps = new PermissionSet (PermissionState.None);
898 permissions.Add (action, ps);
899 } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
900 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
901 permissions [action] = ps;
903 ps.AddPermission (perm);
907 public Constant GetNamedValue (string name)
909 if (named_values == null)
912 for (int i = 0; i < named_values.Count; ++i) {
913 if (named_values [i].Value.Name == name)
914 return named_values [i].Value.Expr as Constant;
920 public CharSet GetCharSetValue ()
922 return (CharSet)System.Enum.Parse (typeof (CharSet), ((Constant) PosArguments [0].Expr).GetValue ().ToString ());
925 public bool HasField (string fieldName)
927 if (named_values == null)
930 foreach (var na in named_values) {
931 if (na.Value.Name == fieldName)
939 // Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value
941 public bool IsInternalCall ()
943 MethodImplOptions options = 0;
944 if (PosArguments.Count == 1) {
945 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
946 } else if (HasField ("Value")) {
947 var named = GetNamedValue ("Value");
948 options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ());
951 return (options & MethodImplOptions.InternalCall) != 0;
955 // Returns true for StructLayoutAttribute with LayoutKind.Explicit value
957 public bool IsExplicitLayoutKind ()
959 if (PosArguments.Count != 1)
962 var value = (LayoutKind) System.Enum.Parse (typeof (LayoutKind), ((Constant) PosArguments[0].Expr).GetValue ().ToString ());
963 return value == LayoutKind.Explicit;
966 public Constant GetParameterDefaultValue (out TypeSpec type)
968 var expr = PosArguments[0].Expr;
970 if (expr is TypeCast)
971 expr = ((TypeCast) expr).Child;
974 return expr as Constant;
977 public override bool Equals (object obj)
979 Attribute a = obj as Attribute;
983 return Type == a.Type && Target == a.Target;
986 public override int GetHashCode ()
988 return type.GetHashCode () ^ Target.GetHashCode ();
992 /// Emit attribute for Attributable symbol
994 public void Emit (Dictionary<Attribute, List<Attribute>> allEmitted)
996 var ctor = Resolve ();
1000 var predefined = context.Module.PredefinedAttributes;
1002 AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage);
1003 if ((usage_attr.ValidOn & Target) == 0) {
1004 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
1005 "It is valid on `{1}' declarations only",
1006 GetSignatureForError (), GetValidTargets ());
1010 AttributeEncoder encoder = new AttributeEncoder (false);
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;
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 ());
1024 } else if (Type == predefined.Guid) {
1026 string v = ((StringConstant) arg_expr).Value;
1028 } catch (Exception e) {
1029 Error_AttributeEmitError (e.Message);
1032 } else if (Type == predefined.AttributeUsage) {
1033 int v = ((IntConstant)((EnumConstant) arg_expr).Child).Value;
1035 context.Compiler.Report.Error (591, Location, "Invalid value for argument to `{0}' attribute",
1036 "System.AttributeUsage");
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");
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");
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.");
1058 arg_expr.EncodeAttributeValue (context, encoder, pt);
1062 if (named_values != null) {
1063 encoder.Stream.Write ((ushort) named_values.Count);
1064 foreach (var na in named_values) {
1065 if (na.Key is FieldExpr)
1066 encoder.Stream.Write ((byte) 0x53);
1068 encoder.Stream.Write ((byte) 0x54);
1070 encoder.Encode (na.Key.Type);
1071 encoder.Encode (na.Value.Name);
1072 na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type);
1075 encoder.EncodeEmptyNamedArguments ();
1078 byte[] cdata = encoder.ToArray ();
1081 foreach (Attributable target in targets)
1082 target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
1083 } catch (Exception e) {
1084 Error_AttributeEmitError (e.Message);
1088 if (!usage_attr.AllowMultiple && allEmitted != null) {
1089 if (allEmitted.ContainsKey (this)) {
1090 var a = allEmitted [this];
1092 a = new List<Attribute> (2);
1093 allEmitted [this] = a;
1097 allEmitted.Add (this, null);
1101 if (!RootContext.VerifyClsCompliance)
1104 // Here we are testing attribute arguments for array usage (error 3016)
1105 if (Owner.IsClsComplianceRequired ()) {
1106 if (PosArguments != null)
1107 PosArguments.CheckArrayAsAttribute (context.Compiler);
1109 if (NamedArguments == null)
1112 NamedArguments.CheckArrayAsAttribute (context.Compiler);
1116 private Expression GetValue ()
1118 if (PosArguments == null || PosArguments.Count < 1)
1121 return PosArguments [0].Expr;
1124 public string GetString ()
1126 Expression e = GetValue ();
1127 if (e is StringConstant)
1128 return ((StringConstant)e).Value;
1132 public bool GetBoolean ()
1134 Expression e = GetValue ();
1135 if (e is BoolConstant)
1136 return ((BoolConstant)e).Value;
1140 public TypeSpec GetArgumentType ()
1142 TypeOf e = GetValue () as TypeOf;
1145 return e.TypeArgument;
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 throw new NotSupportedException ("ET");
1153 protected override Expression DoResolve (ResolveContext ec)
1155 throw new NotImplementedException ();
1158 public override void Emit (EmitContext ec)
1160 throw new NotImplementedException ();
1166 /// For global attributes (assembly, module) we need special handling.
1167 /// Attributes can be located in the several files
1169 public class GlobalAttribute : Attribute
1171 public readonly NamespaceEntry ns;
1173 public GlobalAttribute (NamespaceEntry ns, string target, ATypeNameExpression expression,
1174 Arguments[] args, Location loc, bool nameEscaped):
1175 base (target, expression, args, loc, nameEscaped)
1182 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1183 // each time a new file is parsed. However, we need to use the NamespaceEntry
1184 // in effect where the attribute was used. Since code elsewhere cannot assume
1185 // that the NamespaceEntry is right, just overwrite it.
1187 // Precondition: RootContext.ToplevelTypes == null
1189 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1190 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1192 RootContext.ToplevelTypes.NamespaceEntry = ns;
1195 protected override bool IsSecurityActionValid (bool for_assembly)
1197 return base.IsSecurityActionValid (true);
1202 RootContext.ToplevelTypes.NamespaceEntry = null;
1205 protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
1209 return base.ResolveAsTypeTerminal (expr, ec);
1216 protected override MethodSpec ResolveConstructor (ResolveContext ec)
1220 return base.ResolveConstructor (ec);
1227 protected override bool ResolveNamedArguments (ResolveContext ec)
1231 return base.ResolveNamedArguments (ec);
1239 public class Attributes {
1240 public readonly List<Attribute> Attrs;
1242 public Attributes (Attribute a)
1244 Attrs = new List<Attribute> ();
1248 public Attributes (List<Attribute> attrs)
1253 public void AddAttributes (List<Attribute> attrs)
1255 Attrs.AddRange (attrs);
1258 public void AttachTo (Attributable attributable, IMemberContext context)
1260 foreach (Attribute a in Attrs)
1261 a.AttachTo (attributable, context);
1264 public Attributes Clone ()
1266 var al = new List<Attribute> (Attrs.Count);
1267 foreach (Attribute a in Attrs)
1268 al.Add (a.Clone ());
1270 return new Attributes (al);
1274 /// Checks whether attribute target is valid for the current element
1276 public bool CheckTargets ()
1278 foreach (Attribute a in Attrs) {
1279 if (!a.CheckTarget ())
1285 public Attribute Search (PredefinedAttribute t)
1287 return Search (null, t);
1290 public Attribute Search (string explicitTarget, PredefinedAttribute t)
1292 foreach (Attribute a in Attrs) {
1293 if (explicitTarget != null && a.ExplicitTarget != explicitTarget)
1296 if (a.ResolveType () == t)
1303 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1305 public Attribute[] SearchMulti (PredefinedAttribute t)
1307 List<Attribute> ar = null;
1309 foreach (Attribute a in Attrs) {
1310 if (a.ResolveType () == t) {
1312 ar = new List<Attribute> (Attrs.Count);
1317 return ar == null ? null : ar.ToArray ();
1324 Dictionary<Attribute, List<Attribute>> ld = Attrs.Count > 1 ? new Dictionary<Attribute, List<Attribute>> () : null;
1326 foreach (Attribute a in Attrs)
1329 if (ld == null || ld.Count == 0)
1332 foreach (var d in ld) {
1333 if (d.Value == null)
1336 Attribute a = d.Key;
1338 foreach (Attribute collision in d.Value)
1339 a.Report.SymbolRelatedToPreviousError (collision.Location, "");
1341 a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
1342 a.GetSignatureForError ());
1346 public bool Contains (PredefinedAttribute t)
1348 return Search (t) != null;
1352 public struct AttributeEncoder
1355 public enum EncodedTypeProperties
1359 TypeParameter = 1 << 1
1362 const ushort Version = 1;
1364 public static readonly byte[] Empty;
1366 public readonly BinaryWriter Stream;
1368 static AttributeEncoder ()
1370 Empty = new byte[4];
1371 Array.Copy (BitConverter.GetBytes (Version), Empty, 2);
1374 public AttributeEncoder (bool empty)
1381 Stream = new BinaryWriter (new MemoryStream ());
1382 Stream.Write (Version);
1385 public void Encode (byte value)
1387 Stream.Write (value);
1390 public void Encode (short value)
1392 Stream.Write (value);
1395 public void Encode (int value)
1397 Stream.Write (value);
1400 public void Encode (uint value)
1402 Stream.Write (value);
1405 public void Encode (string value)
1407 if (value == null) {
1408 Stream.Write ((byte) 0xFF);
1412 var buf = Encoding.UTF8.GetBytes(value);
1413 WriteCompressedValue (buf.Length);
1417 public EncodedTypeProperties Encode (TypeSpec type)
1419 if (type == TypeManager.bool_type) {
1420 Stream.Write ((byte) 0x02);
1421 } else if (type == TypeManager.char_type) {
1422 Stream.Write ((byte) 0x03);
1423 } else if (type == TypeManager.sbyte_type) {
1424 Stream.Write ((byte) 0x04);
1425 } else if (type == TypeManager.byte_type) {
1426 Stream.Write ((byte) 0x05);
1427 } else if (type == TypeManager.short_type) {
1428 Stream.Write ((byte) 0x06);
1429 } else if (type == TypeManager.ushort_type) {
1430 Stream.Write ((byte) 0x07);
1431 } else if (type == TypeManager.int32_type) {
1432 Stream.Write ((byte) 0x08);
1433 } else if (type == TypeManager.uint32_type) {
1434 Stream.Write ((byte) 0x09);
1435 } else if (type == TypeManager.int64_type) {
1436 Stream.Write ((byte) 0x0A);
1437 } else if (type == TypeManager.uint64_type) {
1438 Stream.Write ((byte) 0x0B);
1439 } else if (type == TypeManager.float_type) {
1440 Stream.Write ((byte) 0x0C);
1441 } else if (type == TypeManager.double_type) {
1442 Stream.Write ((byte) 0x0D);
1443 } else if (type == TypeManager.string_type) {
1444 Stream.Write ((byte) 0x0E);
1445 } else if (type == TypeManager.type_type) {
1446 Stream.Write ((byte) 0x50);
1447 } else if (type == TypeManager.object_type) {
1448 Stream.Write ((byte) 0x51);
1449 } else if (TypeManager.IsEnumType (type)) {
1450 Stream.Write ((byte) 0x55);
1451 EncodeTypeName (type);
1452 } else if (type.IsArray) {
1453 Stream.Write ((byte) 0x1D);
1454 return Encode (TypeManager.GetElementType (type));
1455 } else if (type == InternalType.Dynamic) {
1456 Stream.Write ((byte) 0x51);
1457 return EncodedTypeProperties.DynamicType;
1460 return EncodedTypeProperties.None;
1463 public void EncodeTypeName (TypeSpec type)
1465 var old_type = type.GetMetaInfo ();
1466 Encode (type.MemberDefinition.IsImported ? old_type.AssemblyQualifiedName : old_type.FullName);
1470 // Encodes single property named argument per call
1472 public void EncodeNamedPropertyArgument (PropertySpec property, Constant value)
1474 Stream.Write ((ushort) 1); // length
1475 Stream.Write ((byte) 0x54); // property
1476 Encode (property.MemberType);
1477 Encode (property.Name);
1478 value.EncodeAttributeValue (null, this, property.MemberType);
1482 // Encodes single field named argument per call
1484 public void EncodeNamedFieldArgument (FieldSpec field, Constant value)
1486 Stream.Write ((ushort) 1); // length
1487 Stream.Write ((byte) 0x53); // field
1488 Encode (field.MemberType);
1489 Encode (field.Name);
1490 value.EncodeAttributeValue (null, this, field.MemberType);
1493 public void EncodeNamedArguments<T> (T[] members, Constant[] values) where T : MemberSpec, IInterfaceMemberSpec
1495 Stream.Write ((ushort) members.Length);
1497 for (int i = 0; i < members.Length; ++i)
1499 var member = members[i];
1501 if (member.Kind == MemberKind.Field)
1502 Stream.Write ((byte) 0x53);
1503 else if (member.Kind == MemberKind.Property)
1504 Stream.Write ((byte) 0x54);
1506 throw new NotImplementedException (member.Kind.ToString ());
1508 Encode (member.MemberType);
1509 Encode (member.Name);
1510 values [i].EncodeAttributeValue (null, this, member.MemberType);
1514 public void EncodeEmptyNamedArguments ()
1516 Stream.Write ((ushort) 0);
1519 void WriteCompressedValue (int value)
1522 Stream.Write ((byte) value);
1526 if (value < 0x4000) {
1527 Stream.Write ((byte) (0x80 | (value >> 8)));
1528 Stream.Write ((byte) value);
1532 Stream.Write (value);
1535 public byte[] ToArray ()
1537 return ((MemoryStream) Stream.BaseStream).ToArray ();
1543 /// Helper class for attribute verification routine.
1545 static class AttributeTester
1547 public enum Result {
1554 /// Returns true if parameters of two compared methods are CLS-Compliant.
1555 /// It tests differing only in ref or out, or in array rank.
1557 public static Result AreOverloadedMethodParamsClsCompliant (AParametersCollection pa, AParametersCollection pb)
1559 TypeSpec [] types_a = pa.Types;
1560 TypeSpec [] types_b = pb.Types;
1561 if (types_a == null || types_b == null)
1564 if (types_a.Length != types_b.Length)
1567 Result result = Result.Ok;
1568 for (int i = 0; i < types_b.Length; ++i) {
1569 TypeSpec aType = types_a [i];
1570 TypeSpec bType = types_b [i];
1572 var ac_a = aType as ArrayContainer;
1573 var ac_b = aType as ArrayContainer;
1575 if (ac_a != null && ac_b != null) {
1576 if (ac_a.Rank != ac_b.Rank && ac_a.Element == ac_b.Element) {
1577 result = Result.RefOutArrayError;
1581 if (ac_a.Element.IsArray || ac_b.Element.IsArray) {
1582 result = Result.ArrayArrayError;
1590 const Parameter.Modifier out_ref_mod = (Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
1591 if ((pa.FixedParameters[i].ModFlags & out_ref_mod) != (pb.FixedParameters[i].ModFlags & out_ref_mod))
1592 result = Result.RefOutArrayError;
1598 /// Common method for Obsolete error/warning reporting.
1600 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report)
1603 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1607 if (oa.Message == null || oa.Message.Length == 0) {
1608 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1611 Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1616 // Predefined attribute types
1618 public class PredefinedAttributes
1620 // Build-in attributes
1621 public readonly PredefinedAttribute ParamArray;
1622 public readonly PredefinedAttribute Out;
1624 // Optional attributes
1625 public readonly PredefinedAttribute Obsolete;
1626 public readonly PredefinedAttribute DllImport;
1627 public readonly PredefinedAttribute MethodImpl;
1628 public readonly PredefinedAttribute MarshalAs;
1629 public readonly PredefinedAttribute In;
1630 public readonly PredefinedAttribute IndexerName;
1631 public readonly PredefinedAttribute Conditional;
1632 public readonly PredefinedAttribute CLSCompliant;
1633 public readonly PredefinedAttribute Security;
1634 public readonly PredefinedAttribute Required;
1635 public readonly PredefinedAttribute Guid;
1636 public readonly PredefinedAttribute AssemblyCulture;
1637 public readonly PredefinedAttribute AssemblyVersion;
1638 public readonly PredefinedAttribute AssemblyAlgorithmId;
1639 public readonly PredefinedAttribute AssemblyFlags;
1640 public readonly PredefinedAttribute AssemblyFileVersion;
1641 public readonly PredefinedAttribute ComImport;
1642 public readonly PredefinedAttribute CoClass;
1643 public readonly PredefinedAttribute AttributeUsage;
1644 public readonly PredefinedAttribute DefaultParameterValue;
1645 public readonly PredefinedAttribute OptionalParameter;
1646 public readonly PredefinedAttribute UnverifiableCode;
1649 //public readonly PredefinedAttribute DefaultCharset;
1650 public readonly PredefinedAttribute TypeForwarder;
1651 public readonly PredefinedAttribute FixedBuffer;
1652 public readonly PredefinedAttribute CompilerGenerated;
1653 public readonly PredefinedAttribute InternalsVisibleTo;
1654 public readonly PredefinedAttribute RuntimeCompatibility;
1655 public readonly PredefinedAttribute DebuggerHidden;
1656 public readonly PredefinedAttribute UnsafeValueType;
1659 public readonly PredefinedAttribute Extension;
1662 public readonly PredefinedDynamicAttribute Dynamic;
1665 // Optional types which are used as types and for member lookup
1667 public readonly PredefinedAttribute DefaultMember;
1668 public readonly PredefinedDecimalAttribute DecimalConstant;
1669 public readonly PredefinedAttribute StructLayout;
1670 public readonly PredefinedAttribute FieldOffset;
1672 public PredefinedAttributes (ModuleContainer module)
1674 ParamArray = new PredefinedAttribute (module, "System", "ParamArrayAttribute");
1675 Out = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OutAttribute");
1676 ParamArray.Resolve (Location.Null);
1677 Out.Resolve (Location.Null);
1679 Obsolete = new PredefinedAttribute (module, "System", "ObsoleteAttribute");
1680 DllImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DllImportAttribute");
1681 MethodImpl = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "MethodImplAttribute");
1682 MarshalAs = new PredefinedAttribute (module, "System.Runtime.InteropServices", "MarshalAsAttribute");
1683 In = new PredefinedAttribute (module, "System.Runtime.InteropServices", "InAttribute");
1684 IndexerName = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IndexerNameAttribute");
1685 Conditional = new PredefinedAttribute (module, "System.Diagnostics", "ConditionalAttribute");
1686 CLSCompliant = new PredefinedAttribute (module, "System", "CLSCompliantAttribute");
1687 Security = new PredefinedAttribute (module, "System.Security.Permissions", "SecurityAttribute");
1688 Required = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1689 Guid = new PredefinedAttribute (module, "System.Runtime.InteropServices", "GuidAttribute");
1690 AssemblyCulture = new PredefinedAttribute (module, "System.Reflection", "AssemblyCultureAttribute");
1691 AssemblyVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyVersionAttribute");
1692 AssemblyAlgorithmId = new PredefinedAttribute (module, "System.Reflection", "AssemblyAlgorithmIdAttribute");
1693 AssemblyFlags = new PredefinedAttribute (module, "System.Reflection", "AssemblyFlagsAttribute");
1694 AssemblyFileVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyFileVersionAttribute");
1695 ComImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "ComImportAttribute");
1696 CoClass = new PredefinedAttribute (module, "System.Runtime.InteropServices", "CoClassAttribute");
1697 AttributeUsage = new PredefinedAttribute (module, "System", "AttributeUsageAttribute");
1698 DefaultParameterValue = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1699 OptionalParameter = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OptionalAttribute");
1700 UnverifiableCode = new PredefinedAttribute (module, "System.Security", "UnverifiableCodeAttribute");
1702 //DefaultCharset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
1703 TypeForwarder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1704 FixedBuffer = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "FixedBufferAttribute");
1705 CompilerGenerated = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1706 InternalsVisibleTo = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1707 RuntimeCompatibility = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1708 DebuggerHidden = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerHiddenAttribute");
1709 UnsafeValueType = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1711 Extension = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "ExtensionAttribute");
1713 Dynamic = new PredefinedDynamicAttribute (module, "System.Runtime.CompilerServices", "DynamicAttribute");
1715 DefaultMember = new PredefinedAttribute (module, "System.Reflection", "DefaultMemberAttribute");
1716 DecimalConstant = new PredefinedDecimalAttribute (module, "System.Runtime.CompilerServices", "DecimalConstantAttribute");
1717 StructLayout = new PredefinedAttribute (module, "System.Runtime.InteropServices", "StructLayoutAttribute");
1718 FieldOffset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "FieldOffsetAttribute");
1720 // TODO: Should define only attributes which are used for comparison
1721 const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
1722 System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly;
1724 foreach (var fi in GetType ().GetFields (all_fields)) {
1725 ((PredefinedAttribute) fi.GetValue (this)).Define ();
1730 public class PredefinedAttribute : PredefinedType
1732 protected MethodSpec ctor;
1733 List<PropertySpec> properties;
1735 public PredefinedAttribute (ModuleContainer module, string ns, string name)
1736 : base (module, MemberKind.Class, ns, name)
1742 public MethodSpec Constructor {
1750 public static bool operator == (TypeSpec type, PredefinedAttribute pa)
1752 return type == pa.type && pa.type != null;
1755 public static bool operator != (TypeSpec type, PredefinedAttribute pa)
1757 return type != pa.type;
1760 public override int GetHashCode ()
1762 return base.GetHashCode ();
1765 public override bool Equals (object obj)
1767 throw new NotSupportedException ();
1770 public void EmitAttribute (ConstructorBuilder builder)
1772 if (ResolveBuilder ())
1773 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1776 public void EmitAttribute (MethodBuilder builder)
1778 if (ResolveBuilder ())
1779 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1782 public void EmitAttribute (PropertyBuilder builder)
1784 if (ResolveBuilder ())
1785 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1788 public void EmitAttribute (FieldBuilder builder)
1790 if (ResolveBuilder ())
1791 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1794 public void EmitAttribute (FieldBuilder builder, AttributeEncoder argsEncoded)
1796 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1799 public void EmitAttribute (TypeBuilder builder)
1801 if (ResolveBuilder ())
1802 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1805 public void EmitAttribute (TypeBuilder builder, AttributeEncoder argsEncoded)
1807 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1810 public void EmitAttribute (AssemblyBuilder builder)
1812 if (ResolveBuilder ())
1813 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1816 public void EmitAttribute (ModuleBuilder builder)
1818 if (ResolveBuilder ())
1819 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1822 public void EmitAttribute (ParameterBuilder builder)
1824 if (ResolveBuilder ())
1825 builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
1828 public void EmitAttribute (ParameterBuilder builder, AttributeEncoder argsEncoded)
1830 builder.SetCustomAttribute (GetCtorMetaInfo (), argsEncoded.ToArray ());
1833 ConstructorInfo GetCtorMetaInfo ()
1835 return (ConstructorInfo) ctor.GetMetaInfo ();
1838 public PropertySpec GetProperty (string name, TypeSpec memberType, Location loc)
1842 if (properties != null) {
1843 spec = properties.Find (l => l.Name == name);
1849 spec = TypeManager.GetPredefinedProperty (type, name, loc, memberType);
1852 if (properties == null) {
1853 properties = new List<PropertySpec> ();
1856 properties.Add (spec);
1863 public bool ResolveBuilder ()
1869 // Handle all parameter-less attributes as optional
1874 ctor = TypeManager.GetPredefinedConstructor (type, Location.Null, TypeSpec.EmptyTypes);
1875 return ctor != null;
1878 public bool ResolveConstructor (Location loc, params TypeSpec[] argType)
1881 throw new InternalErrorException ("Predefined ctor redefined");
1883 if (Resolve (loc) == null)
1886 ctor = TypeManager.GetPredefinedConstructor (type, loc, argType);
1887 return ctor != null;
1891 public class PredefinedDecimalAttribute : PredefinedAttribute
1893 public PredefinedDecimalAttribute (ModuleContainer module, string ns, string name)
1894 : base (module, ns, name)
1898 public void EmitAttribute (ParameterBuilder builder, decimal value, Location loc)
1900 if (Resolve (loc) == null)
1903 if (ctor == null && !ResolveConstructor (loc, TypeManager.byte_type, TypeManager.byte_type, TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
1906 int[] bits = decimal.GetBits (value);
1907 AttributeEncoder encoder = new AttributeEncoder (false);
1908 encoder.Encode ((byte) (bits[3] >> 16));
1909 encoder.Encode ((byte) (bits[3] >> 31));
1910 encoder.Encode ((uint) bits[2]);
1911 encoder.Encode ((uint) bits[1]);
1912 encoder.Encode ((uint) bits[0]);
1913 encoder.EncodeEmptyNamedArguments ();
1915 EmitAttribute (builder, encoder);
1918 public void EmitAttribute (FieldBuilder builder, decimal value, Location loc)
1920 if (Resolve (loc) == null)
1923 if (ctor == null && !ResolveConstructor (loc, TypeManager.byte_type, TypeManager.byte_type, TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
1926 int[] bits = decimal.GetBits (value);
1927 AttributeEncoder encoder = new AttributeEncoder (false);
1928 encoder.Encode ((byte) (bits[3] >> 16));
1929 encoder.Encode ((byte) (bits[3] >> 31));
1930 encoder.Encode ((uint) bits[2]);
1931 encoder.Encode ((uint) bits[1]);
1932 encoder.Encode ((uint) bits[0]);
1933 encoder.EncodeEmptyNamedArguments ();
1935 EmitAttribute (builder, encoder);
1939 public class PredefinedDynamicAttribute : PredefinedAttribute
1943 public PredefinedDynamicAttribute (ModuleContainer module, string ns, string name)
1944 : base (module, ns, name)
1948 public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
1950 if (ResolveTransformationCtor (loc)) {
1951 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1952 builder.SetCustomAttribute (cab);
1956 public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
1958 if (ResolveTransformationCtor (loc)) {
1959 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1960 builder.SetCustomAttribute (cab);
1964 public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
1966 if (ResolveTransformationCtor (loc)) {
1967 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1968 builder.SetCustomAttribute (cab);
1972 public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
1974 if (ResolveTransformationCtor (loc)) {
1975 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1976 builder.SetCustomAttribute (cab);
1981 // When any element of the type is a dynamic type
1983 // This method builds a transformation array for dynamic types
1984 // used in places where DynamicAttribute cannot be applied to.
1985 // It uses bool flag when type is of dynamic type and each
1986 // section always starts with "false" for some reason.
1988 // LAMESPEC: This should be part of C# specification
1990 // Example: Func<dynamic, int, dynamic[]>
1991 // Transformation: { false, true, false, false, true }
1993 static bool[] GetTransformationFlags (TypeSpec t)
1996 var ac = t as ArrayContainer;
1998 element = GetTransformationFlags (ac.Element);
1999 if (element == null)
2002 bool[] res = new bool[element.Length + 1];
2004 Array.Copy (element, 0, res, 1, element.Length);
2012 List<bool> transform = null;
2013 var targs = t.TypeArguments;
2014 for (int i = 0; i < targs.Length; ++i) {
2015 element = GetTransformationFlags (targs[i]);
2016 if (element != null) {
2017 if (transform == null) {
2018 transform = new List<bool> ();
2019 for (int ii = 0; ii <= i; ++ii)
2020 transform.Add (false);
2023 transform.AddRange (element);
2024 } else if (transform != null) {
2025 transform.Add (false);
2029 if (transform != null)
2030 return transform.ToArray ();
2033 if (t == InternalType.Dynamic)
2034 return new bool[] { true };
2039 bool ResolveTransformationCtor (Location loc)
2044 if (Resolve (loc) == null)
2047 tctor = TypeManager.GetPredefinedConstructor (type, Location.Null, ArrayContainer.MakeType (TypeManager.bool_type));
2048 return tctor != null;