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.Diagnostics;
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.InteropServices;
19 using System.Runtime.CompilerServices;
20 using System.Security;
21 using System.Security.Permissions;
25 namespace Mono.CSharp {
28 /// Base class for objects that can have Attributes applied to them.
30 public abstract class Attributable {
32 // Holds all attributes attached to this element
34 protected Attributes attributes;
36 public void AddAttributes (Attributes attrs, IMemberContext context)
41 if (attributes == null)
44 throw new NotImplementedException ();
46 attributes.AttachTo (this, context);
49 public Attributes OptAttributes {
59 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
61 public abstract void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa);
64 /// Returns one AttributeTarget for this element.
66 public abstract AttributeTargets AttributeTargets { get; }
68 public abstract bool IsClsComplianceRequired ();
71 /// Gets list of valid attribute targets for explicit target declaration.
72 /// The first array item is default target. Don't break this rule.
74 public abstract string[] ValidAttributeTargets { get; }
77 public class Attribute : Expression
79 public readonly string ExplicitTarget;
80 public AttributeTargets Target;
81 readonly ATypeNameExpression expression;
83 Arguments PosArguments;
84 Arguments NamedArguments;
88 readonly bool nameEscaped;
91 // An attribute can be attached to multiple targets (e.g. multiple fields)
93 protected Attributable[] targets;
96 // A member context for the attribute, it's much easier to hold it here
97 // than trying to pull it during resolve
99 IMemberContext context;
101 public static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
102 static Assembly orig_sec_assembly;
103 public static readonly object[] EmptyObject = new object [0];
105 IList<KeyValuePair<MemberExpr, NamedArgument>> named_values;
107 // Cache for parameter-less attributes
108 static Dictionary<TypeSpec, MethodSpec> att_cache;
110 public Attribute (string target, ATypeNameExpression expr, Arguments[] args, Location loc, bool nameEscaped)
112 this.expression = expr;
114 PosArguments = args [0];
115 NamedArguments = args [1];
118 ExplicitTarget = target;
119 this.nameEscaped = nameEscaped;
122 public Attribute Clone ()
124 Attribute a = new Attribute (ExplicitTarget, expression, null, loc, nameEscaped);
125 a.PosArguments = PosArguments;
126 a.NamedArguments = NamedArguments;
135 public static void Reset ()
137 att_cache = new Dictionary<TypeSpec, MethodSpec> ();
141 // When the same attribute is attached to multiple fiels
142 // we use @target field as a list of targets. The attribute
143 // has to be resolved only once but emitted for each target.
145 public virtual void AttachTo (Attributable target, IMemberContext context)
147 if (this.targets == null) {
148 this.targets = new Attributable[] { target };
149 this.context = context;
153 // Resize target array
154 Attributable[] new_array = new Attributable [this.targets.Length + 1];
155 targets.CopyTo (new_array, 0);
156 new_array [targets.Length] = target;
157 this.targets = new_array;
159 // No need to update context, different targets cannot have
160 // different contexts, it's enough to remove same attributes
161 // from secondary members.
163 target.OptAttributes = null;
166 static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name)
168 rc.Report.Error (617, name.Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
169 "must be fields which are not readonly, static, const or read-write properties which are " +
170 "public and not static",
174 static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name)
176 rc.Report.Error (655, name.Location,
177 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
181 public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc)
183 context.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression");
186 public void Error_MissingGuidAttribute ()
188 Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
191 public void Error_MisusedExtensionAttribute ()
193 Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
196 public void Error_MisusedDynamicAttribute ()
198 Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
202 /// This is rather hack. We report many emit attribute error with same error to be compatible with
203 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
205 public void Error_AttributeEmitError (string inner)
207 Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
208 TypeManager.CSharpName (Type), inner);
211 public void Error_InvalidSecurityParent ()
213 Error_AttributeEmitError ("it is attached to invalid parent");
222 protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
224 return expr.ResolveAsTypeTerminal (ec, false);
227 TypeSpec ResolvePossibleAttributeType (ATypeNameExpression expr, ref bool is_attr)
229 TypeExpr te = ResolveAsTypeTerminal (expr, context);
233 TypeSpec t = te.Type;
237 Report.SymbolRelatedToPreviousError (t);
238 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
244 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
246 void ResolveAttributeType ()
248 SessionReportPrinter resolve_printer = new SessionReportPrinter ();
249 ReportPrinter prev_recorder = context.Compiler.Report.SetPrinter (resolve_printer);
251 bool t1_is_attr = false;
252 bool t2_is_attr = false;
254 ATypeNameExpression expanded = null;
257 t1 = ResolvePossibleAttributeType (expression, ref t1_is_attr);
262 expanded = (ATypeNameExpression) expression.Clone (null);
263 expanded.Name += "Attribute";
265 t2 = ResolvePossibleAttributeType (expanded, ref t2_is_attr);
268 resolve_printer.EndSession ();
270 context.Compiler.Report.SetPrinter (prev_recorder);
273 if (t1_is_attr && t2_is_attr) {
274 Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
275 GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ());
276 resolve_error = true;
290 resolve_printer.Merge (prev_recorder);
291 resolve_error = true;
294 public virtual TypeSpec ResolveType ()
296 if (Type == null && !resolve_error)
297 ResolveAttributeType ();
301 public override string GetSignatureForError ()
304 return TypeManager.CSharpName (Type);
306 return expression.GetSignatureForError ();
309 public bool HasSecurityAttribute {
311 PredefinedAttribute pa = context.Compiler.PredefinedAttributes.Security;
312 return pa.IsDefined && TypeSpec.IsBaseClass (type, pa.Type, false);
316 public bool IsValidSecurityAttribute ()
318 return HasSecurityAttribute && IsSecurityActionValid (false);
321 static bool IsValidArgumentType (TypeSpec t)
324 t = TypeManager.GetElementType (t);
326 return t == TypeManager.string_type ||
327 TypeManager.IsPrimitiveType (t) ||
328 TypeManager.IsEnumType (t) ||
329 t == TypeManager.object_type ||
330 t == TypeManager.type_type;
333 // TODO: Don't use this ambiguous value
335 get { return expression.Name; }
338 void ApplyModuleCharSet (ResolveContext rc)
340 if (Type != context.Compiler.PredefinedAttributes.DllImport)
343 if (!RootContext.ToplevelTypes.HasDefaultCharSet)
346 const string CharSetEnumMember = "CharSet";
347 if (NamedArguments == null) {
348 NamedArguments = new Arguments (1);
350 foreach (NamedArgument a in NamedArguments) {
351 if (a.Name == CharSetEnumMember)
356 var char_set = rc.Compiler.MetaImporter.ImportType (typeof (CharSet)); // TODO: typeof
357 NamedArguments.Add (new NamedArgument (CharSetEnumMember, loc,
358 Constant.CreateConstant (rc, char_set, RootContext.ToplevelTypes.DefaultCharSet, Location)));
361 public Report Report {
362 get { return context.Compiler.Report; }
365 public MethodSpec Resolve ()
370 resolve_error = true;
374 ResolveAttributeType ();
379 if (Type.IsAbstract) {
380 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
384 ObsoleteAttribute obsolete_attr = Type.GetAttributeObsolete ();
385 if (obsolete_attr != null) {
386 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location, Report);
390 // Try if the attribute is simple has been resolved before
391 if (PosArguments == null && NamedArguments == null) {
392 if (att_cache.TryGetValue (Type, out ctor)) {
393 resolve_error = false;
398 ResolveContext rc = new ResolveContext (context, ResolveContext.Options.ConstantScope);
399 ctor = ResolveConstructor (rc);
404 ApplyModuleCharSet (rc);
406 if (NamedArguments != null && !ResolveNamedArguments (rc)) {
410 resolve_error = false;
414 protected virtual MethodSpec ResolveConstructor (ResolveContext ec)
416 if (PosArguments != null) {
418 PosArguments.Resolve (ec, out dynamic);
420 Error_AttributeArgumentIsDynamic (ec.MemberContext, loc);
425 return ConstructorLookup (ec, Type, ref PosArguments, loc);
428 protected virtual bool ResolveNamedArguments (ResolveContext ec)
430 int named_arg_count = NamedArguments.Count;
431 var seen_names = new List<string> (named_arg_count);
433 named_values = new List<KeyValuePair<MemberExpr, NamedArgument>> (named_arg_count);
435 foreach (NamedArgument a in NamedArguments) {
436 string name = a.Name;
437 if (seen_names.Contains (name)) {
438 ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name);
442 seen_names.Add (name);
446 Expression member = Expression.MemberLookup (ec, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
448 if (member == null) {
449 member = Expression.MemberLookup (null, ec.CurrentType, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
451 if (member != null) {
452 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
453 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
459 Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name);
463 if (!(member is PropertyExpr || member is FieldExpr)) {
464 Error_InvalidNamedArgument (ec, a);
468 ObsoleteAttribute obsolete_attr;
470 if (member is PropertyExpr) {
471 var pi = ((PropertyExpr) member).PropertyInfo;
473 if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) {
474 ec.Report.SymbolRelatedToPreviousError (pi);
475 Error_InvalidNamedArgument (ec, a);
479 if (!IsValidArgumentType (member.Type)) {
480 ec.Report.SymbolRelatedToPreviousError (pi);
481 Error_InvalidNamedArgumentType (ec, a);
485 obsolete_attr = pi.GetAttributeObsolete ();
486 pi.MemberDefinition.SetIsAssigned ();
488 var fi = ((FieldExpr) member).Spec;
490 if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) {
491 Error_InvalidNamedArgument (ec, a);
495 if (!IsValidArgumentType (member.Type)) {
496 ec.Report.SymbolRelatedToPreviousError (fi);
497 Error_InvalidNamedArgumentType (ec, a);
501 obsolete_attr = fi.GetAttributeObsolete ();
502 fi.MemberDefinition.SetIsAssigned ();
505 if (obsolete_attr != null && !context.IsObsolete)
506 AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location, Report);
508 if (a.Type != member.Type) {
509 a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location);
513 named_values.Add (new KeyValuePair<MemberExpr, NamedArgument> ((MemberExpr) member, a));
520 /// Get a string containing a list of valid targets for the attribute 'attr'
522 public string GetValidTargets ()
524 StringBuilder sb = new StringBuilder ();
525 AttributeTargets targets = Type.GetAttributeUsage (context.Compiler.PredefinedAttributes.AttributeUsage).ValidOn;
527 if ((targets & AttributeTargets.Assembly) != 0)
528 sb.Append ("assembly, ");
530 if ((targets & AttributeTargets.Module) != 0)
531 sb.Append ("module, ");
533 if ((targets & AttributeTargets.Class) != 0)
534 sb.Append ("class, ");
536 if ((targets & AttributeTargets.Struct) != 0)
537 sb.Append ("struct, ");
539 if ((targets & AttributeTargets.Enum) != 0)
540 sb.Append ("enum, ");
542 if ((targets & AttributeTargets.Constructor) != 0)
543 sb.Append ("constructor, ");
545 if ((targets & AttributeTargets.Method) != 0)
546 sb.Append ("method, ");
548 if ((targets & AttributeTargets.Property) != 0)
549 sb.Append ("property, indexer, ");
551 if ((targets & AttributeTargets.Field) != 0)
552 sb.Append ("field, ");
554 if ((targets & AttributeTargets.Event) != 0)
555 sb.Append ("event, ");
557 if ((targets & AttributeTargets.Interface) != 0)
558 sb.Append ("interface, ");
560 if ((targets & AttributeTargets.Parameter) != 0)
561 sb.Append ("parameter, ");
563 if ((targets & AttributeTargets.Delegate) != 0)
564 sb.Append ("delegate, ");
566 if ((targets & AttributeTargets.ReturnValue) != 0)
567 sb.Append ("return, ");
569 if ((targets & AttributeTargets.GenericParameter) != 0)
570 sb.Append ("type parameter, ");
572 return sb.Remove (sb.Length - 2, 2).ToString ();
575 public AttributeUsageAttribute GetAttributeUsageAttribute ()
578 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
579 // But because a lot of attribute class code must be rewritten will be better to wait...
583 return DefaultUsageAttribute;
585 AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)((Constant) PosArguments [0].Expr).GetValue ());
587 var field = GetPropertyValue ("AllowMultiple") as BoolConstant;
589 usage_attribute.AllowMultiple = field.Value;
591 field = GetPropertyValue ("Inherited") as BoolConstant;
593 usage_attribute.Inherited = field.Value;
595 return usage_attribute;
599 /// Returns custom name of indexer
601 public string GetIndexerAttributeValue ()
604 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
605 // But because a lot of attribute class code must be rewritten will be better to wait...
611 return ((Constant) PosArguments [0].Expr).GetValue () as string;
615 /// Returns condition of ConditionalAttribute
617 public string GetConditionalAttributeValue ()
620 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
621 // But because a lot of attribute class code must be rewritten will be better to wait...
627 return ((Constant) PosArguments[0].Expr).GetValue () as string;
631 /// Creates the instance of ObsoleteAttribute from this attribute instance
633 public ObsoleteAttribute GetObsoleteAttribute ()
636 // corlib only case when obsolete is used before is resolved
637 var c = type.MemberDefinition as Class;
638 if (c != null && !c.HasMembersDefined)
641 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
642 // But because a lot of attribute class code must be rewritten will be better to wait...
649 if (PosArguments == null)
650 return new ObsoleteAttribute ();
652 string msg = ((Constant) PosArguments[0].Expr).GetValue () as string;
653 if (PosArguments.Count == 1)
654 return new ObsoleteAttribute (msg);
656 return new ObsoleteAttribute (msg, ((BoolConstant) PosArguments[1].Expr).Value);
660 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
661 /// before ApplyAttribute. We need to resolve the arguments.
662 /// This situation occurs when class deps is differs from Emit order.
664 public bool GetClsCompliantAttributeValue ()
667 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
668 // But because a lot of attribute class code must be rewritten will be better to wait...
674 return ((BoolConstant) PosArguments[0].Expr).Value;
677 public TypeSpec GetCoClassAttributeValue ()
685 return GetArgumentType ();
688 public bool CheckTarget ()
690 string[] valid_targets = Owner.ValidAttributeTargets;
691 if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
692 Target = Owner.AttributeTargets;
696 // TODO: we can skip the first item
697 if (Array.Exists (valid_targets, i => i == ExplicitTarget)) {
698 switch (ExplicitTarget) {
699 case "return": Target = AttributeTargets.ReturnValue; return true;
700 case "param": Target = AttributeTargets.Parameter; return true;
701 case "field": Target = AttributeTargets.Field; return true;
702 case "method": Target = AttributeTargets.Method; return true;
703 case "property": Target = AttributeTargets.Property; return true;
705 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
708 StringBuilder sb = new StringBuilder ();
709 foreach (string s in valid_targets) {
713 sb.Remove (sb.Length - 2, 2);
714 Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
715 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
720 /// Tests permitted SecurityAction for assembly or other types
722 protected virtual bool IsSecurityActionValid (bool for_assembly)
724 SecurityAction action = GetSecurityActionValue ();
727 case SecurityAction.Demand:
728 case SecurityAction.Assert:
729 case SecurityAction.Deny:
730 case SecurityAction.PermitOnly:
731 case SecurityAction.LinkDemand:
732 case SecurityAction.InheritanceDemand:
737 case SecurityAction.RequestMinimum:
738 case SecurityAction.RequestOptional:
739 case SecurityAction.RequestRefuse:
745 Error_AttributeEmitError ("SecurityAction is out of range");
749 Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
753 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
755 return (SecurityAction) ((Constant) PosArguments[0].Expr).GetTypedValue ();
759 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
761 /// <returns></returns>
762 public void ExtractSecurityPermissionSet (Dictionary<SecurityAction, PermissionSet> permissions)
764 Type orig_assembly_type = null;
766 if (Type.MemberDefinition is TypeContainer) {
767 if (!RootContext.StdLib) {
768 orig_assembly_type = System.Type.GetType (Type.GetMetaInfo ().FullName);
770 string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
771 if (orig_version_path == null) {
772 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
776 if (orig_sec_assembly == null) {
777 string file = Path.Combine (orig_version_path, Driver.OutputFile);
778 orig_sec_assembly = Assembly.LoadFile (file);
781 orig_assembly_type = orig_sec_assembly.GetType (Type.GetMetaInfo ().FullName, true);
782 if (orig_assembly_type == null) {
783 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' " +
784 "was not found in previous version of assembly");
790 SecurityAttribute sa;
793 // For all non-selfreferencing security attributes we can avoid all hacks
794 if (orig_assembly_type == null) {
795 args = new object[PosArguments.Count];
796 for (int j = 0; j < args.Length; ++j) {
797 args[j] = ((Constant) PosArguments[j].Expr).GetTypedValue ();
800 sa = (SecurityAttribute) Activator.CreateInstance (Type.GetMetaInfo (), args);
802 if (named_values != null) {
803 for (int i = 0; i < named_values.Count; ++i) {
804 PropertyInfo pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
805 pi.SetValue (sa, ((Constant) named_values [i].Value.Expr).GetTypedValue (), null);
809 // HACK: All security attributes have same ctor syntax
810 args = new object[] { GetSecurityActionValue () };
811 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, args);
813 // All types are from newly created assembly but for invocation with old one we need to convert them
814 if (named_values != null) {
815 for (int i = 0; i < named_values.Count; ++i) {
816 PropertyInfo emited_pi = ((PropertyExpr) named_values[i].Key).PropertyInfo.MetaInfo;
817 // FIXME: We are missing return type filter
818 // TODO: pi can be null
819 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name);
821 pi.SetValue (sa, ((Constant) named_values[i].Value.Expr).GetTypedValue (), null);
827 perm = sa.CreatePermission ();
828 SecurityAction action = (SecurityAction) args [0];
830 // IS is correct because for corlib we are using an instance from old corlib
831 if (!(perm is System.Security.CodeAccessPermission)) {
833 case SecurityAction.Demand:
834 action = (SecurityAction)13;
836 case SecurityAction.LinkDemand:
837 action = (SecurityAction)14;
839 case SecurityAction.InheritanceDemand:
840 action = (SecurityAction)15;
846 if (!permissions.TryGetValue (action, out ps)) {
847 if (sa is PermissionSetAttribute)
848 ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
850 ps = new PermissionSet (PermissionState.None);
852 permissions.Add (action, ps);
853 } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
854 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
855 permissions [action] = ps;
857 ps.AddPermission (perm);
860 public Constant GetPropertyValue (string name)
862 if (named_values == null)
865 for (int i = 0; i < named_values.Count; ++i) {
866 if (named_values [i].Value.Name == name)
867 return named_values [i].Value.Expr as Constant;
874 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
875 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
876 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
879 public UnmanagedMarshal GetMarshal (Attributable attr)
881 UnmanagedType UnmanagedType;
882 if (!RootContext.StdLib || pos_values [0].GetType () != typeof (UnmanagedType))
883 UnmanagedType = (UnmanagedType) System.Enum.ToObject (typeof (UnmanagedType), pos_values [0]);
885 UnmanagedType = (UnmanagedType) pos_values [0];
887 object value = GetFieldValue ("SizeParamIndex");
888 if (value != null && UnmanagedType != UnmanagedType.LPArray) {
889 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
893 object o = GetFieldValue ("ArraySubType");
894 UnmanagedType array_sub_type = o == null ? (UnmanagedType) 0x50 /* NATIVE_MAX */ : (UnmanagedType) o;
896 switch (UnmanagedType) {
897 case UnmanagedType.CustomMarshaler: {
898 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
899 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
900 if (define_custom == null) {
901 Report.RuntimeMissingSupport (Location, "set marshal info");
905 object [] args = new object [4];
906 args [0] = GetFieldValue ("MarshalTypeRef");
907 args [1] = GetFieldValue ("MarshalCookie");
908 args [2] = GetFieldValue ("MarshalType");
909 args [3] = Guid.Empty;
910 return (UnmanagedMarshal) define_custom.Invoke (null, args);
912 case UnmanagedType.LPArray: {
913 object size_const = GetFieldValue ("SizeConst");
914 object size_param_index = GetFieldValue ("SizeParamIndex");
916 if ((size_const != null) || (size_param_index != null)) {
917 MethodInfo define_array = typeof (UnmanagedMarshal).GetMethod ("DefineLPArrayInternal",
918 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
919 if (define_array == null) {
920 Report.RuntimeMissingSupport (Location, "set marshal info");
924 object [] args = new object [3];
925 args [0] = array_sub_type;
926 args [1] = size_const == null ? -1 : size_const;
927 args [2] = size_param_index == null ? -1 : size_param_index;
928 return (UnmanagedMarshal) define_array.Invoke (null, args);
931 return UnmanagedMarshal.DefineLPArray (array_sub_type);
933 case UnmanagedType.SafeArray:
934 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
936 case UnmanagedType.ByValArray:
937 FieldBase fm = attr as FieldBase;
939 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
942 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
944 case UnmanagedType.ByValTStr:
945 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
948 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
952 object GetFieldValue (string name)
955 if (field_info_arr == null)
958 foreach (FieldInfo fi in field_info_arr) {
960 return GetValue (field_values_arr [i]);
966 static object GetValue (object value)
968 if (value is EnumConstant)
969 return ((EnumConstant) value).GetValue ();
976 public CharSet GetCharSetValue ()
978 return (CharSet)System.Enum.Parse (typeof (CharSet), ((Constant) PosArguments [0].Expr).GetValue ().ToString ());
981 public bool HasField (string fieldName)
983 if (named_values == null)
986 foreach (var na in named_values) {
987 if (na.Value.Name == fieldName)
994 public bool IsInternalMethodImplAttribute {
996 if (Type != context.Compiler.PredefinedAttributes.MethodImpl)
999 MethodImplOptions options;
1000 if (PosArguments[0].Type.GetMetaInfo () != typeof (MethodImplOptions))
1001 options = (MethodImplOptions) System.Enum.ToObject (typeof (MethodImplOptions), ((Constant) PosArguments[0].Expr).GetValue ());
1003 options = (MethodImplOptions) ((Constant) PosArguments [0].Expr).GetValue ();
1005 return (options & MethodImplOptions.InternalCall) != 0;
1009 public LayoutKind GetLayoutKindValue ()
1011 if (!RootContext.StdLib || PosArguments[0].Type.GetMetaInfo () != typeof (LayoutKind))
1012 return (LayoutKind) System.Enum.ToObject (typeof (LayoutKind), ((Constant) PosArguments[0].Expr).GetValue ());
1014 return (LayoutKind) ((Constant) PosArguments[0].Expr).GetValue ();
1017 public Constant GetParameterDefaultValue (out TypeSpec type)
1019 var expr = PosArguments[0].Expr;
1021 if (expr is TypeCast)
1022 expr = ((TypeCast) expr).Child;
1025 return expr as Constant;
1028 public override bool Equals (object obj)
1030 Attribute a = obj as Attribute;
1034 return Type == a.Type && Target == a.Target;
1037 public override int GetHashCode ()
1039 return type.GetHashCode () ^ Target.GetHashCode ();
1043 /// Emit attribute for Attributable symbol
1045 public void Emit (Dictionary<Attribute, List<Attribute>> allEmitted)
1047 var ctor = Resolve ();
1051 var predefined = context.Compiler.PredefinedAttributes;
1053 AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage);
1054 if ((usage_attr.ValidOn & Target) == 0) {
1055 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
1056 "It is valid on `{1}' declarations only",
1057 GetSignatureForError (), GetValidTargets ());
1061 AttributeEncoder encoder = new AttributeEncoder (false);
1063 if (PosArguments != null) {
1064 var param_types = ctor.Parameters.Types;
1065 for (int j = 0; j < PosArguments.Count; ++j) {
1066 var pt = param_types[j];
1067 var arg_expr = PosArguments[j].Expr;
1069 if (Type == predefined.IndexerName || Type == predefined.Conditional) {
1070 string v = ((StringConstant) arg_expr).Value;
1071 if (!Tokenizer.IsValidIdentifier (v) || Tokenizer.IsKeyword (v)) {
1072 context.Compiler.Report.Error (633, arg_expr.Location,
1073 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
1075 } else if (Type == predefined.Guid) {
1077 string v = ((StringConstant) arg_expr).Value;
1079 } catch (Exception e) {
1080 Error_AttributeEmitError (e.Message);
1083 } else if (Type == predefined.AttributeUsage) {
1084 int v = ((IntConstant)((EnumConstant) arg_expr).Child).Value;
1086 context.Compiler.Report.Error (591, Location, "Invalid value for argument to `{0}' attribute",
1087 "System.AttributeUsage");
1089 } else if (Type == predefined.MethodImpl && pt == TypeManager.short_type &&
1090 !System.Enum.IsDefined (typeof (MethodImplOptions), ((Constant) arg_expr).GetValue ().ToString ())) {
1091 Error_AttributeEmitError ("Incorrect argument value.");
1096 arg_expr.EncodeAttributeValue (context, encoder, pt);
1100 if (named_values != null) {
1101 encoder.Stream.Write ((ushort) named_values.Count);
1102 foreach (var na in named_values) {
1103 if (na.Key is FieldExpr)
1104 encoder.Stream.Write ((byte) 0x53);
1106 encoder.Stream.Write ((byte) 0x54);
1108 encoder.Encode (na.Key.Type);
1109 encoder.Encode (na.Value.Name);
1110 na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type);
1113 encoder.Stream.Write ((ushort) 0);
1116 byte[] cdata = encoder.ToArray ();
1119 foreach (Attributable target in targets)
1120 target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
1121 } catch (Exception e) {
1122 Error_AttributeEmitError (e.Message);
1126 if (!usage_attr.AllowMultiple && allEmitted != null) {
1127 if (allEmitted.ContainsKey (this)) {
1128 var a = allEmitted [this];
1130 a = new List<Attribute> (2);
1131 allEmitted [this] = a;
1135 allEmitted.Add (this, null);
1139 if (!RootContext.VerifyClsCompliance)
1142 // Here we are testing attribute arguments for array usage (error 3016)
1143 if (Owner.IsClsComplianceRequired ()) {
1144 if (PosArguments != null)
1145 PosArguments.CheckArrayAsAttribute (context.Compiler);
1147 if (NamedArguments == null)
1150 NamedArguments.CheckArrayAsAttribute (context.Compiler);
1154 private Expression GetValue ()
1156 if (PosArguments == null || PosArguments.Count < 1)
1159 return PosArguments [0].Expr;
1162 public string GetString ()
1164 Expression e = GetValue ();
1165 if (e is StringConstant)
1166 return ((StringConstant)e).Value;
1170 public bool GetBoolean ()
1172 Expression e = GetValue ();
1173 if (e is BoolConstant)
1174 return ((BoolConstant)e).Value;
1178 public TypeSpec GetArgumentType ()
1180 TypeOf e = GetValue () as TypeOf;
1183 return e.TypeArgument;
1186 public override Expression CreateExpressionTree (ResolveContext ec)
1188 throw new NotSupportedException ("ET");
1191 protected override Expression DoResolve (ResolveContext ec)
1193 throw new NotImplementedException ();
1196 public override void Emit (EmitContext ec)
1198 throw new NotImplementedException ();
1204 /// For global attributes (assembly, module) we need special handling.
1205 /// Attributes can be located in the several files
1207 public class GlobalAttribute : Attribute
1209 public readonly NamespaceEntry ns;
1211 public GlobalAttribute (NamespaceEntry ns, string target, ATypeNameExpression expression,
1212 Arguments[] args, Location loc, bool nameEscaped):
1213 base (target, expression, args, loc, nameEscaped)
1218 public override void AttachTo (Attributable target, IMemberContext context)
1220 if (ExplicitTarget == "assembly") {
1221 base.AttachTo (CodeGen.Assembly, context);
1225 if (ExplicitTarget == "module") {
1226 base.AttachTo (RootContext.ToplevelTypes, context);
1230 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget);
1235 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1236 // each time a new file is parsed. However, we need to use the NamespaceEntry
1237 // in effect where the attribute was used. Since code elsewhere cannot assume
1238 // that the NamespaceEntry is right, just overwrite it.
1240 // Precondition: RootContext.ToplevelTypes == null
1242 if (RootContext.ToplevelTypes.NamespaceEntry != null)
1243 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1245 RootContext.ToplevelTypes.NamespaceEntry = ns;
1248 protected override bool IsSecurityActionValid (bool for_assembly)
1250 return base.IsSecurityActionValid (true);
1255 RootContext.ToplevelTypes.NamespaceEntry = null;
1258 protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IMemberContext ec)
1262 return base.ResolveAsTypeTerminal (expr, ec);
1269 protected override MethodSpec ResolveConstructor (ResolveContext ec)
1273 return base.ResolveConstructor (ec);
1280 protected override bool ResolveNamedArguments (ResolveContext ec)
1284 return base.ResolveNamedArguments (ec);
1292 public class Attributes {
1293 public readonly List<Attribute> Attrs;
1295 public Attributes (Attribute a)
1297 Attrs = new List<Attribute> ();
1301 public Attributes (List<Attribute> attrs)
1306 public void AddAttributes (List<Attribute> attrs)
1308 Attrs.AddRange (attrs);
1311 public void AttachTo (Attributable attributable, IMemberContext context)
1313 foreach (Attribute a in Attrs)
1314 a.AttachTo (attributable, context);
1317 public Attributes Clone ()
1319 var al = new List<Attribute> (Attrs.Count);
1320 foreach (Attribute a in Attrs)
1321 al.Add (a.Clone ());
1323 return new Attributes (al);
1327 /// Checks whether attribute target is valid for the current element
1329 public bool CheckTargets ()
1331 foreach (Attribute a in Attrs) {
1332 if (!a.CheckTarget ())
1338 public Attribute Search (PredefinedAttribute t)
1340 foreach (Attribute a in Attrs) {
1341 if (a.ResolveType () == t)
1348 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1350 public Attribute[] SearchMulti (PredefinedAttribute t)
1352 List<Attribute> ar = null;
1354 foreach (Attribute a in Attrs) {
1355 if (a.ResolveType () == t) {
1357 ar = new List<Attribute> (Attrs.Count);
1362 return ar == null ? null : ar.ToArray ();
1369 Dictionary<Attribute, List<Attribute>> ld = Attrs.Count > 1 ? new Dictionary<Attribute, List<Attribute>> () : null;
1371 foreach (Attribute a in Attrs)
1374 if (ld == null || ld.Count == 0)
1377 foreach (var d in ld) {
1378 if (d.Value == null)
1381 Attribute a = d.Key;
1383 foreach (Attribute collision in d.Value)
1384 a.Report.SymbolRelatedToPreviousError (collision.Location, "");
1386 a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
1387 a.GetSignatureForError ());
1391 public bool Contains (PredefinedAttribute t)
1393 return Search (t) != null;
1397 public struct AttributeEncoder
1400 public enum EncodedTypeProperties
1404 TypeParameter = 1 << 1
1407 public readonly BinaryWriter Stream;
1409 public AttributeEncoder (bool empty)
1416 Stream = new BinaryWriter (new MemoryStream ());
1417 const ushort version = 1;
1418 Stream.Write (version);
1421 public void Encode (string value)
1424 throw new ArgumentNullException ();
1426 var buf = Encoding.UTF8.GetBytes(value);
1427 WriteCompressedValue (buf.Length);
1431 public EncodedTypeProperties Encode (TypeSpec type)
1433 if (type == TypeManager.bool_type) {
1434 Stream.Write ((byte) 0x02);
1435 } else if (type == TypeManager.char_type) {
1436 Stream.Write ((byte) 0x03);
1437 } else if (type == TypeManager.sbyte_type) {
1438 Stream.Write ((byte) 0x04);
1439 } else if (type == TypeManager.byte_type) {
1440 Stream.Write ((byte) 0x05);
1441 } else if (type == TypeManager.short_type) {
1442 Stream.Write ((byte) 0x06);
1443 } else if (type == TypeManager.ushort_type) {
1444 Stream.Write ((byte) 0x07);
1445 } else if (type == TypeManager.int32_type) {
1446 Stream.Write ((byte) 0x08);
1447 } else if (type == TypeManager.uint32_type) {
1448 Stream.Write ((byte) 0x09);
1449 } else if (type == TypeManager.int64_type) {
1450 Stream.Write ((byte) 0x0A);
1451 } else if (type == TypeManager.uint64_type) {
1452 Stream.Write ((byte) 0x0B);
1453 } else if (type == TypeManager.float_type) {
1454 Stream.Write ((byte) 0x0C);
1455 } else if (type == TypeManager.double_type) {
1456 Stream.Write ((byte) 0x0D);
1457 } else if (type == TypeManager.string_type) {
1458 Stream.Write ((byte) 0x0E);
1459 } else if (type == TypeManager.type_type) {
1460 Stream.Write ((byte) 0x50);
1461 } else if (type == TypeManager.object_type) {
1462 Stream.Write ((byte) 0x51);
1463 } else if (TypeManager.IsEnumType (type)) {
1464 Stream.Write ((byte) 0x55);
1465 EncodeTypeName (type);
1466 } else if (type.IsArray) {
1467 Stream.Write ((byte) 0x1D);
1468 return Encode (TypeManager.GetElementType (type));
1469 } else if (type == InternalType.Dynamic) {
1470 Stream.Write ((byte) 0x51);
1471 return EncodedTypeProperties.DynamicType;
1474 return EncodedTypeProperties.None;
1477 public void EncodeTypeName (TypeSpec type)
1479 var old_type = type.GetMetaInfo ();
1480 Encode (type.MemberDefinition.IsImported ? old_type.AssemblyQualifiedName : old_type.FullName);
1483 void WriteCompressedValue (int value)
1486 Stream.Write ((byte) value);
1490 if (value < 0x4000) {
1491 Stream.Write ((byte) (0x80 | (value >> 8)));
1492 Stream.Write ((byte) value);
1496 Stream.Write (value);
1499 public byte[] ToArray ()
1501 return ((MemoryStream) Stream.BaseStream).ToArray ();
1507 /// Helper class for attribute verification routine.
1509 static class AttributeTester
1511 public enum Result {
1518 /// Returns true if parameters of two compared methods are CLS-Compliant.
1519 /// It tests differing only in ref or out, or in array rank.
1521 public static Result AreOverloadedMethodParamsClsCompliant (AParametersCollection pa, AParametersCollection pb)
1523 TypeSpec [] types_a = pa.Types;
1524 TypeSpec [] types_b = pb.Types;
1525 if (types_a == null || types_b == null)
1528 if (types_a.Length != types_b.Length)
1531 Result result = Result.Ok;
1532 for (int i = 0; i < types_b.Length; ++i) {
1533 TypeSpec aType = types_a [i];
1534 TypeSpec bType = types_b [i];
1536 var ac_a = aType as ArrayContainer;
1537 var ac_b = aType as ArrayContainer;
1539 if (ac_a != null && ac_b != null) {
1540 if (ac_a.Rank != ac_b.Rank && ac_a.Element == ac_b.Element) {
1541 result = Result.RefOutArrayError;
1545 if (ac_a.Element.IsArray || ac_b.Element.IsArray) {
1546 result = Result.ArrayArrayError;
1554 const Parameter.Modifier out_ref_mod = (Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
1555 if ((pa.FixedParameters[i].ModFlags & out_ref_mod) != (pb.FixedParameters[i].ModFlags & out_ref_mod))
1556 result = Result.RefOutArrayError;
1561 public static void VerifyModulesClsCompliance (CompilerContext ctx)
1563 Module[] modules = ctx.GlobalRootNamespace.Modules;
1564 if (modules == null)
1567 // The first module is generated assembly
1568 for (int i = 1; i < modules.Length; ++i) {
1569 Module module = modules [i];
1570 if (!GetClsCompliantAttributeValue (module, null)) {
1571 ctx.Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1572 "to match the assembly", module.Name);
1578 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider, Assembly a)
1580 object[] cls_attr = attribute_provider.GetCustomAttributes (typeof (CLSCompliantAttribute), false);
1581 if (cls_attr.Length == 0) {
1585 return GetClsCompliantAttributeValue (a, null);
1588 return ((CLSCompliantAttribute)cls_attr [0]).IsCompliant;
1592 /// Common method for Obsolete error/warning reporting.
1594 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report)
1597 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1601 if (oa.Message == null || oa.Message.Length == 0) {
1602 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1605 Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1609 public class PredefinedAttributes
1612 public readonly PredefinedAttribute ParamArray;
1613 public readonly PredefinedAttribute Out;
1616 public readonly PredefinedAttribute Obsolete;
1617 public readonly PredefinedAttribute DllImport;
1618 public readonly PredefinedAttribute MethodImpl;
1619 public readonly PredefinedAttribute MarshalAs;
1620 public readonly PredefinedAttribute In;
1621 public readonly PredefinedAttribute IndexerName;
1622 public readonly PredefinedAttribute Conditional;
1623 public readonly PredefinedAttribute CLSCompliant;
1624 public readonly PredefinedAttribute Security;
1625 public readonly PredefinedAttribute Required;
1626 public readonly PredefinedAttribute Guid;
1627 public readonly PredefinedAttribute AssemblyCulture;
1628 public readonly PredefinedAttribute AssemblyVersion;
1629 public readonly PredefinedAttribute AssemblyAlgorithmId;
1630 public readonly PredefinedAttribute AssemblyFlags;
1631 public readonly PredefinedAttribute ComImport;
1632 public readonly PredefinedAttribute CoClass;
1633 public readonly PredefinedAttribute AttributeUsage;
1634 public readonly PredefinedAttribute DefaultParameterValue;
1635 public readonly PredefinedAttribute OptionalParameter;
1638 public readonly PredefinedAttribute DefaultCharset;
1639 public readonly PredefinedAttribute TypeForwarder;
1640 public readonly PredefinedAttribute FixedBuffer;
1641 public readonly PredefinedAttribute CompilerGenerated;
1642 public readonly PredefinedAttribute InternalsVisibleTo;
1643 public readonly PredefinedAttribute RuntimeCompatibility;
1644 public readonly PredefinedAttribute DebuggerHidden;
1645 public readonly PredefinedAttribute UnsafeValueType;
1648 public readonly PredefinedAttribute Extension;
1651 public readonly PredefinedDynamicAttribute Dynamic;
1654 // Optional types which are used as types and for member lookup
1656 public readonly PredefinedAttribute DefaultMember;
1657 public readonly PredefinedAttribute DecimalConstant;
1658 public readonly PredefinedAttribute StructLayout;
1659 public readonly PredefinedAttribute FieldOffset;
1661 public PredefinedAttributes ()
1663 ParamArray = new PredefinedAttribute ("System", "ParamArrayAttribute");
1664 Out = new PredefinedAttribute ("System.Runtime.InteropServices", "OutAttribute");
1666 Obsolete = new PredefinedAttribute ("System", "ObsoleteAttribute");
1667 DllImport = new PredefinedAttribute ("System.Runtime.InteropServices", "DllImportAttribute");
1668 MethodImpl = new PredefinedAttribute ("System.Runtime.CompilerServices", "MethodImplAttribute");
1669 MarshalAs = new PredefinedAttribute ("System.Runtime.InteropServices", "MarshalAsAttribute");
1670 In = new PredefinedAttribute ("System.Runtime.InteropServices", "InAttribute");
1671 IndexerName = new PredefinedAttribute ("System.Runtime.CompilerServices", "IndexerNameAttribute");
1672 Conditional = new PredefinedAttribute ("System.Diagnostics", "ConditionalAttribute");
1673 CLSCompliant = new PredefinedAttribute ("System", "CLSCompliantAttribute");
1674 Security = new PredefinedAttribute ("System.Security.Permissions", "SecurityAttribute");
1675 Required = new PredefinedAttribute ("System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1676 Guid = new PredefinedAttribute ("System.Runtime.InteropServices", "GuidAttribute");
1677 AssemblyCulture = new PredefinedAttribute ("System.Reflection", "AssemblyCultureAttribute");
1678 AssemblyVersion = new PredefinedAttribute ("System.Reflection", "AssemblyVersionAttribute");
1679 AssemblyAlgorithmId = new PredefinedAttribute ("System.Reflection", "AssemblyAlgorithmIdAttribute");
1680 AssemblyFlags = new PredefinedAttribute ("System.Reflection", "AssemblyFlagsAttribute");
1681 ComImport = new PredefinedAttribute ("System.Runtime.InteropServices", "ComImportAttribute");
1682 CoClass = new PredefinedAttribute ("System.Runtime.InteropServices", "CoClassAttribute");
1683 AttributeUsage = new PredefinedAttribute ("System", "AttributeUsageAttribute");
1684 DefaultParameterValue = new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1685 OptionalParameter = new PredefinedAttribute ("System.Runtime.InteropServices", "OptionalAttribute");
1687 DefaultCharset = new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultCharSetAttribute");
1688 TypeForwarder = new PredefinedAttribute ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1689 FixedBuffer = new PredefinedAttribute ("System.Runtime.CompilerServices", "FixedBufferAttribute");
1690 CompilerGenerated = new PredefinedAttribute ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1691 InternalsVisibleTo = new PredefinedAttribute ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1692 RuntimeCompatibility = new PredefinedAttribute ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1693 DebuggerHidden = new PredefinedAttribute ("System.Diagnostics", "DebuggerHiddenAttribute");
1694 UnsafeValueType = new PredefinedAttribute ("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1696 Extension = new PredefinedAttribute ("System.Runtime.CompilerServices", "ExtensionAttribute");
1698 Dynamic = new PredefinedDynamicAttribute ("System.Runtime.CompilerServices", "DynamicAttribute");
1700 DefaultMember = new PredefinedAttribute ("System.Reflection", "DefaultMemberAttribute");
1701 DecimalConstant = new PredefinedAttribute ("System.Runtime.CompilerServices", "DecimalConstantAttribute");
1702 StructLayout = new PredefinedAttribute ("System.Runtime.InteropServices", "StructLayoutAttribute");
1703 FieldOffset = new PredefinedAttribute ("System.Runtime.InteropServices", "FieldOffsetAttribute");
1706 public void Initialize (CompilerContext ctx)
1708 foreach (FieldInfo fi in GetType ().GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
1709 ((PredefinedAttribute) fi.GetValue (this)).Initialize (ctx, true);
1714 public class PredefinedAttribute
1716 protected TypeSpec type;
1717 CustomAttributeBuilder cab;
1719 readonly string ns, name;
1720 CompilerContext compiler;
1722 static readonly TypeSpec NotFound = InternalType.Null;
1724 public PredefinedAttribute (string ns, string name)
1730 public static bool operator == (TypeSpec type, PredefinedAttribute pa)
1732 return type == pa.type;
1735 public static bool operator != (TypeSpec type, PredefinedAttribute pa)
1737 return type != pa.type;
1740 public ConstructorInfo Constructor {
1741 get { return ctor == null ? null : (ConstructorInfo) ctor.GetMetaInfo (); }
1744 public override int GetHashCode ()
1746 return base.GetHashCode ();
1749 public string GetSignatureForError ()
1751 return ns + "." + name;
1754 public override bool Equals (object obj)
1756 throw new NotSupportedException ();
1759 public void EmitAttribute (ConstructorBuilder builder)
1761 if (ResolveBuilder ())
1762 builder.SetCustomAttribute (cab);
1765 public void EmitAttribute (MethodBuilder builder)
1767 if (ResolveBuilder ())
1768 builder.SetCustomAttribute (cab);
1771 public void EmitAttribute (PropertyBuilder builder)
1773 if (ResolveBuilder ())
1774 builder.SetCustomAttribute (cab);
1777 public void EmitAttribute (FieldBuilder builder)
1779 if (ResolveBuilder ())
1780 builder.SetCustomAttribute (cab);
1783 public void EmitAttribute (TypeBuilder builder)
1785 if (ResolveBuilder ())
1786 builder.SetCustomAttribute (cab);
1789 public void EmitAttribute (AssemblyBuilder builder)
1791 if (ResolveBuilder ())
1792 builder.SetCustomAttribute (cab);
1795 public void EmitAttribute (ParameterBuilder builder)
1797 if (ResolveBuilder ())
1798 builder.SetCustomAttribute (cab);
1801 public bool IsDefined {
1802 get { return type != null && type != NotFound; }
1805 public void Initialize (CompilerContext ctx, bool canFail)
1807 this.compiler = ctx;
1811 public bool Resolve (bool canFail)
1820 type = TypeManager.CoreLookupType (compiler, ns, name, MemberKind.Class, !canFail);
1829 bool ResolveBuilder ()
1835 // Handle all parameter-less attributes as optional
1837 if (!Resolve (true))
1840 var ci = TypeManager.GetPredefinedConstructor (type, Location.Null, TypeSpec.EmptyTypes);
1844 cab = new CustomAttributeBuilder ((ConstructorInfo) ci.GetMetaInfo (), new object[0]);
1848 public bool ResolveConstructor (Location loc, params TypeSpec[] argType)
1851 throw new InternalErrorException ("Predefined ctor redefined");
1853 if (!Resolve (false))
1856 ctor = TypeManager.GetPredefinedConstructor (type, loc, argType);
1857 return ctor != null;
1860 public TypeSpec Type {
1861 get { return type; }
1865 public class PredefinedDynamicAttribute : PredefinedAttribute
1869 public PredefinedDynamicAttribute (string ns, string name)
1874 public void EmitAttribute (FieldBuilder builder, TypeSpec type)
1876 if (ResolveTransformationCtor ()) {
1877 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1878 builder.SetCustomAttribute (cab);
1882 public void EmitAttribute (ParameterBuilder builder, TypeSpec type)
1884 if (ResolveTransformationCtor ()) {
1885 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1886 builder.SetCustomAttribute (cab);
1890 public void EmitAttribute (PropertyBuilder builder, TypeSpec type)
1892 if (ResolveTransformationCtor ()) {
1893 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1894 builder.SetCustomAttribute (cab);
1898 public void EmitAttribute (TypeBuilder builder, TypeSpec type)
1900 if (ResolveTransformationCtor ()) {
1901 var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
1902 builder.SetCustomAttribute (cab);
1907 // When any element of the type is a dynamic type
1909 // This method builds a transformation array for dynamic types
1910 // used in places where DynamicAttribute cannot be applied to.
1911 // It uses bool flag when type is of dynamic type and each
1912 // section always starts with "false" for some reason.
1914 // LAMESPEC: This should be part of C# specification
1916 // Example: Func<dynamic, int, dynamic[]>
1917 // Transformation: { false, true, false, false, true }
1919 static bool[] GetTransformationFlags (TypeSpec t)
1922 var ac = t as ArrayContainer;
1924 element = GetTransformationFlags (ac.Element);
1925 if (element == null)
1928 bool[] res = new bool[element.Length + 1];
1930 Array.Copy (element, 0, res, 1, element.Length);
1938 List<bool> transform = null;
1939 var targs = t.TypeArguments;
1940 for (int i = 0; i < targs.Length; ++i) {
1941 element = GetTransformationFlags (targs[i]);
1942 if (element != null) {
1943 if (transform == null) {
1944 transform = new List<bool> ();
1945 for (int ii = 0; ii <= i; ++ii)
1946 transform.Add (false);
1949 transform.AddRange (element);
1950 } else if (transform != null) {
1951 transform.Add (false);
1955 if (transform != null)
1956 return transform.ToArray ();
1959 if (t == InternalType.Dynamic)
1960 return new bool[] { true };
1965 bool ResolveTransformationCtor ()
1970 if (!Resolve (false))
1973 tctor = TypeManager.GetPredefinedConstructor (type, Location.Null, ArrayContainer.MakeType (TypeManager.bool_type));
1974 return tctor != null;