// // attribute.cs: Attributes handling // // Author: Ravi Pratap (ravi@ximian.com) // Marek Safar (marek.safar@gmail.com) // // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) // Copyright 2003-2008 Novell, Inc. // Copyright 2011-2013 Xamarin Inc // using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text; using System.IO; #if STATIC using SecurityType = System.Collections.Generic.List; using BadImageFormat = IKVM.Reflection.BadImageFormatException; using IKVM.Reflection; using IKVM.Reflection.Emit; #else using SecurityType = System.Collections.Generic.Dictionary; using BadImageFormat = System.BadImageFormatException; using System.Reflection; using System.Reflection.Emit; #endif namespace Mono.CSharp { /// /// Base class for objects that can have Attributes applied to them. /// public abstract class Attributable { // // Holds all attributes attached to this element // protected Attributes attributes; public void AddAttributes (Attributes attrs, IMemberContext context) { if (attrs == null) return; if (attributes == null) attributes = attrs; else attributes.AddAttributes (attrs.Attrs); attrs.AttachTo (this, context); } public Attributes OptAttributes { get { return attributes; } set { attributes = value; } } /// /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder /// public abstract void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa); /// /// Returns one AttributeTarget for this element. /// public abstract AttributeTargets AttributeTargets { get; } public abstract bool IsClsComplianceRequired (); /// /// Gets list of valid attribute targets for explicit target declaration. /// The first array item is default target. Don't break this rule. /// public abstract string[] ValidAttributeTargets { get; } }; public class Attribute { public readonly string ExplicitTarget; public AttributeTargets Target; readonly ATypeNameExpression expression; Arguments pos_args, named_args; bool resolve_error; bool arg_resolved; readonly bool nameEscaped; readonly Location loc; public TypeSpec Type; // // An attribute can be attached to multiple targets (e.g. multiple fields) // Attributable[] targets; // // A member context for the attribute, it's much easier to hold it here // than trying to pull it during resolve // IMemberContext context; public static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All); public static readonly object[] EmptyObject = new object [0]; List> named_values; public Attribute (string target, ATypeNameExpression expr, Arguments[] args, Location loc, bool nameEscaped) { this.expression = expr; if (args != null) { pos_args = args[0]; named_args = args[1]; } this.loc = loc; ExplicitTarget = target; this.nameEscaped = nameEscaped; } public Location Location { get { return loc; } } public Arguments NamedArguments { get { return named_args; } } public Arguments PositionalArguments { get { return pos_args; } } public bool ResolveError { get { return resolve_error; } } public ATypeNameExpression TypeExpression { get { return expression; } } void AddModuleCharSet (ResolveContext rc) { const string dll_import_char_set = "CharSet"; // // Only when not customized by user // if (HasField (dll_import_char_set)) return; if (!rc.Module.PredefinedTypes.CharSet.Define ()) { return; } if (NamedArguments == null) named_args = new Arguments (1); var value = Constant.CreateConstantFromValue (rc.Module.PredefinedTypes.CharSet.TypeSpec, rc.Module.DefaultCharSet, Location); NamedArguments.Add (new NamedArgument (dll_import_char_set, loc, value)); } public Attribute Clone () { Attribute a = new Attribute (ExplicitTarget, expression, null, loc, nameEscaped); a.pos_args = pos_args; a.named_args = NamedArguments; return a; } // // When the same attribute is attached to multiple fiels // we use @target field as a list of targets. The attribute // has to be resolved only once but emitted for each target. // public void AttachTo (Attributable target, IMemberContext context) { if (this.targets == null) { this.targets = new Attributable[] { target }; this.context = context; return; } // When re-attaching global attributes if (context is NamespaceContainer) { this.targets[0] = target; this.context = context; return; } // Resize target array Attributable[] new_array = new Attributable [this.targets.Length + 1]; targets.CopyTo (new_array, 0); new_array [targets.Length] = target; this.targets = new_array; // No need to update context, different targets cannot have // different contexts, it's enough to remove same attributes // from secondary members. target.OptAttributes = null; } public ResolveContext CreateResolveContext () { return new ResolveContext (context, ResolveContext.Options.ConstantScope); } static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name) { rc.Report.Error (617, name.Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " + "must be fields which are not readonly, static, const or read-write properties which are " + "public and not static", name.Name); } static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name) { rc.Report.Error (655, name.Location, "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type", name.Name); } public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc) { context.Module.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression"); } public void Error_MissingGuidAttribute () { Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute"); } public void Error_MisusedExtensionAttribute () { Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ()); } public void Error_MisusedDynamicAttribute () { Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ()); } void Error_AttributeEmitError (string inner) { Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'", Type.GetSignatureForError (), inner); } public void Error_InvalidArgumentValue (TypeSpec attributeType) { Report.Error (591, Location, "Invalid value for argument to `{0}' attribute", attributeType.GetSignatureForError ()); } public void Error_InvalidSecurityParent () { Report.Error (7070, Location, "Security attribute `{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations", Type.GetSignatureForError ()); } Attributable Owner { get { return targets [0]; } } public void SetOwner (Attributable owner) { targets [0] = owner; } /// /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true. /// void ResolveAttributeType (bool comparisonOnly) { var resolve_printer = new SessionReportPrinter (); SessionReportPrinter secondary_printer = null; ReportPrinter prev_recorder = Report.SetPrinter (resolve_printer); bool t1_is_attr = false; bool t2_is_attr = false; TypeSpec t1, t2; ATypeNameExpression expanded = null; // TODO: Additional warnings such as CS0436 are swallowed because we don't // print on success try { t1 = expression.ResolveAsType (context); resolve_printer.EndSession (); if (t1 != null && resolve_printer.ErrorsCount == 0) t1_is_attr = t1.IsAttribute; if (nameEscaped) { t2 = null; } else { expanded = (ATypeNameExpression) expression.Clone (null); expanded.Name += "Attribute"; secondary_printer = new SessionReportPrinter (); Report.SetPrinter (secondary_printer); t2 = expanded.ResolveAsType (context); secondary_printer.EndSession (); if (t2 != null && secondary_printer.ErrorsCount == 0) t2_is_attr = t2.IsAttribute; secondary_printer.EndSession (); } } finally { context.Module.Compiler.Report.SetPrinter (prev_recorder); } if (t1_is_attr && t2_is_attr && t1 != t2) { if (!comparisonOnly) { Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'", GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ()); resolve_error = true; } return; } if (t1_is_attr) { Type = t1; return; } if (t2_is_attr) { Type = t2; return; } if (comparisonOnly) return; resolve_error = true; if (t1 != null) { if (resolve_printer.IsEmpty) { Report.SymbolRelatedToPreviousError (t1); Report.Error (616, Location, "`{0}': is not an attribute class", t1.GetSignatureForError ()); } else { resolve_printer.Merge (prev_recorder); } return; } if (t2 != null) { if (secondary_printer.IsEmpty) { Report.SymbolRelatedToPreviousError (t2); Report.Error (616, Location, "`{0}': is not an attribute class", t2.GetSignatureForError ()); } else { secondary_printer.Merge (prev_recorder); } return; } resolve_printer.Merge (prev_recorder); } public TypeSpec ResolveTypeForComparison () { if (Type == null && !resolve_error) ResolveAttributeType (true); return Type; } public string GetSignatureForError () { if (Type != null) return Type.GetSignatureForError (); return expression.GetSignatureForError (); } public bool HasSecurityAttribute { get { PredefinedAttribute pa = context.Module.PredefinedAttributes.Security; return pa.IsDefined && TypeSpec.IsBaseClass (Type, pa.TypeSpec, false); } } public bool IsValidSecurityAttribute () { return HasSecurityAttribute && IsSecurityActionValid (); } static bool IsValidMethodImplOption (int value) { // // Allow to use AggressiveInlining on any runtime/corlib // MethodImplOptions all = (MethodImplOptions) 256; foreach (MethodImplOptions v in System.Enum.GetValues (typeof (MethodImplOptions))) { all |= v; } return ((MethodImplOptions) value | all) == all; } public static bool IsValidArgumentType (TypeSpec t) { if (t.IsArray) { var ac = (ArrayContainer) t; if (ac.Rank > 1) return false; t = ac.Element; } switch (t.BuiltinType) { case BuiltinTypeSpec.Type.Int: case BuiltinTypeSpec.Type.UInt: case BuiltinTypeSpec.Type.Long: case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.Float: case BuiltinTypeSpec.Type.Double: case BuiltinTypeSpec.Type.Char: case BuiltinTypeSpec.Type.Short: case BuiltinTypeSpec.Type.Bool: case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.Byte: case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.String: case BuiltinTypeSpec.Type.Object: case BuiltinTypeSpec.Type.Dynamic: case BuiltinTypeSpec.Type.Type: return true; } return t.IsEnum; } // TODO: Don't use this ambiguous value public string Name { get { return expression.Name; } } public Report Report { get { return context.Module.Compiler.Report; } } public MethodSpec Resolve () { if (resolve_error) return null; resolve_error = true; arg_resolved = true; if (Type == null) { ResolveAttributeType (false); if (Type == null) return null; } if (Type.IsAbstract) { Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ()); return null; } Type.CheckObsoleteness (context, expression.StartLocation); ResolveContext rc = null; MethodSpec ctor; // Try if the attribute is simple and has been resolved before if (pos_args != null || !context.Module.AttributeConstructorCache.TryGetValue (Type, out ctor)) { rc = CreateResolveContext (); ctor = ResolveConstructor (rc); if (ctor == null) { return null; } if (pos_args == null && ctor.Parameters.IsEmpty) context.Module.AttributeConstructorCache.Add (Type, ctor); } // // Add [module: DefaultCharSet] to all DllImport import attributes // var module = context.Module; if ((Type == module.PredefinedAttributes.DllImport || Type == module.PredefinedAttributes.UnmanagedFunctionPointer) && module.HasDefaultCharSet) { if (rc == null) rc = CreateResolveContext (); AddModuleCharSet (rc); } if (NamedArguments != null) { if (rc == null) rc = CreateResolveContext (); if (!ResolveNamedArguments (rc)) return null; } resolve_error = false; return ctor; } MethodSpec ResolveConstructor (ResolveContext ec) { if (pos_args != null) { bool dynamic; pos_args.Resolve (ec, out dynamic); if (dynamic) { Error_AttributeArgumentIsDynamic (ec.MemberContext, loc); return null; } } return Expression.ConstructorLookup (ec, Type, ref pos_args, loc); } bool ResolveNamedArguments (ResolveContext ec) { int named_arg_count = NamedArguments.Count; var seen_names = new List (named_arg_count); named_values = new List> (named_arg_count); foreach (NamedArgument a in NamedArguments) { string name = a.Name; if (seen_names.Contains (name)) { ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name); continue; } seen_names.Add (name); a.Resolve (ec); Expression member = Expression.MemberLookup (ec, false, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); if (member == null) { member = Expression.MemberLookup (ec, true, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); if (member != null) { // TODO: ec.Report.SymbolRelatedToPreviousError (member); Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc); return false; } } if (member == null){ Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name); return false; } if (!(member is PropertyExpr || member is FieldExpr)) { Error_InvalidNamedArgument (ec, a); return false; } if (member is PropertyExpr) { var pi = ((PropertyExpr) member).PropertyInfo; if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) { ec.Report.SymbolRelatedToPreviousError (pi); Error_InvalidNamedArgument (ec, a); return false; } if (!IsValidArgumentType (member.Type)) { ec.Report.SymbolRelatedToPreviousError (pi); Error_InvalidNamedArgumentType (ec, a); return false; } // if (!context.IsObsolete) pi.CheckObsoleteness (ec, member.StartLocation); pi.MemberDefinition.SetIsAssigned (); } else { var fi = ((FieldExpr) member).Spec; if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) { Error_InvalidNamedArgument (ec, a); return false; } if (!IsValidArgumentType (member.Type)) { ec.Report.SymbolRelatedToPreviousError (fi); Error_InvalidNamedArgumentType (ec, a); return false; } // if (!context.IsObsolete) fi.CheckObsoleteness (ec, member.StartLocation); fi.MemberDefinition.SetIsAssigned (); } if (a.Type != member.Type) { a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location); } if (a.Expr != null) named_values.Add (new KeyValuePair ((MemberExpr) member, a)); } return true; } /// /// Get a string containing a list of valid targets for the attribute 'attr' /// public string GetValidTargets () { StringBuilder sb = new StringBuilder (); AttributeTargets targets = Type.GetAttributeUsage (context.Module.PredefinedAttributes.AttributeUsage).ValidOn; if ((targets & AttributeTargets.Assembly) != 0) sb.Append ("assembly, "); if ((targets & AttributeTargets.Module) != 0) sb.Append ("module, "); if ((targets & AttributeTargets.Class) != 0) sb.Append ("class, "); if ((targets & AttributeTargets.Struct) != 0) sb.Append ("struct, "); if ((targets & AttributeTargets.Enum) != 0) sb.Append ("enum, "); if ((targets & AttributeTargets.Constructor) != 0) sb.Append ("constructor, "); if ((targets & AttributeTargets.Method) != 0) sb.Append ("method, "); if ((targets & AttributeTargets.Property) != 0) sb.Append ("property, indexer, "); if ((targets & AttributeTargets.Field) != 0) sb.Append ("field, "); if ((targets & AttributeTargets.Event) != 0) sb.Append ("event, "); if ((targets & AttributeTargets.Interface) != 0) sb.Append ("interface, "); if ((targets & AttributeTargets.Parameter) != 0) sb.Append ("parameter, "); if ((targets & AttributeTargets.Delegate) != 0) sb.Append ("delegate, "); if ((targets & AttributeTargets.ReturnValue) != 0) sb.Append ("return, "); if ((targets & AttributeTargets.GenericParameter) != 0) sb.Append ("type parameter, "); return sb.Remove (sb.Length - 2, 2).ToString (); } public AttributeUsageAttribute GetAttributeUsageAttribute () { if (!arg_resolved) // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args. // But because a lot of attribute class code must be rewritten will be better to wait... Resolve (); if (resolve_error) return DefaultUsageAttribute; AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets) ((Constant) pos_args[0].Expr).GetValue ()); var field = GetNamedValue ("AllowMultiple") as BoolConstant; if (field != null) usage_attribute.AllowMultiple = field.Value; field = GetNamedValue ("Inherited") as BoolConstant; if (field != null) usage_attribute.Inherited = field.Value; return usage_attribute; } /// /// Returns custom name of indexer /// public string GetIndexerAttributeValue () { if (!arg_resolved) // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args. // But because a lot of attribute class code must be rewritten will be better to wait... Resolve (); if (resolve_error || pos_args.Count != 1 || !(pos_args[0].Expr is Constant)) return null; return ((Constant) pos_args[0].Expr).GetValue () as string; } /// /// Returns condition of ConditionalAttribute /// public string GetConditionalAttributeValue () { if (!arg_resolved) // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args. // But because a lot of attribute class code must be rewritten will be better to wait... Resolve (); if (resolve_error) return null; return ((Constant) pos_args[0].Expr).GetValue () as string; } /// /// Creates the instance of ObsoleteAttribute from this attribute instance /// public ObsoleteAttribute GetObsoleteAttribute () { if (!arg_resolved) { // corlib only case when obsolete is used before is resolved var c = Type.MemberDefinition as Class; if (c != null && !c.HasMembersDefined) c.Define (); // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args. // But because a lot of attribute class code must be rewritten will be better to wait... Resolve (); } if (resolve_error) return null; if (pos_args == null) return new ObsoleteAttribute (); string msg = ((Constant) pos_args[0].Expr).GetValue () as string; if (pos_args.Count == 1) return new ObsoleteAttribute (msg); return new ObsoleteAttribute (msg, ((BoolConstant) pos_args[1].Expr).Value); } /// /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called /// before ApplyAttribute. We need to resolve the arguments. /// This situation occurs when class deps is differs from Emit order. /// public bool GetClsCompliantAttributeValue () { if (!arg_resolved) // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args. // But because a lot of attribute class code must be rewritten will be better to wait... Resolve (); if (resolve_error) return false; return ((BoolConstant) pos_args[0].Expr).Value; } public TypeSpec GetCoClassAttributeValue () { if (!arg_resolved) Resolve (); if (resolve_error) return null; return GetArgumentType (); } public bool CheckTarget () { string[] valid_targets = Owner.ValidAttributeTargets; if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) { Target = Owner.AttributeTargets; return true; } // TODO: we can skip the first item if (Array.Exists (valid_targets, i => i == ExplicitTarget)) { switch (ExplicitTarget) { case "return": Target = AttributeTargets.ReturnValue; return true; case "param": Target = AttributeTargets.Parameter; return true; case "field": Target = AttributeTargets.Field; return true; case "method": Target = AttributeTargets.Method; return true; case "property": Target = AttributeTargets.Property; return true; case "module": Target = AttributeTargets.Module; return true; } throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget); } StringBuilder sb = new StringBuilder (); foreach (string s in valid_targets) { sb.Append (s); sb.Append (", "); } sb.Remove (sb.Length - 2, 2); Report.Warning (657, 1, Location, "`{0}' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are `{1}'. All attributes in this section will be ignored", ExplicitTarget, sb.ToString ()); return false; } /// /// Tests permitted SecurityAction for assembly or other types /// bool IsSecurityActionValid () { Constant c = null; var action = GetSecurityActionValue (ref c); bool for_assembly = Target == AttributeTargets.Assembly || Target == AttributeTargets.Module; switch (action) { #pragma warning disable 618 case SecurityAction.Demand: case SecurityAction.Assert: case SecurityAction.Deny: case SecurityAction.PermitOnly: case SecurityAction.LinkDemand: case SecurityAction.InheritanceDemand: if (!for_assembly) return true; break; case SecurityAction.RequestMinimum: case SecurityAction.RequestOptional: case SecurityAction.RequestRefuse: if (for_assembly) return true; break; #pragma warning restore 618 case null: Report.Error (7048, loc, "First argument of a security attribute `{0}' must be a valid SecurityAction", Type.GetSignatureForError ()); return false; default: Report.Error (7049, c.Location, "Security attribute `{0}' has an invalid SecurityAction value `{1}'", Type.GetSignatureForError (), c.GetValueAsLiteral()); return false; } switch (Target) { case AttributeTargets.Assembly: Report.Error (7050, c.Location, "SecurityAction value `{0}' is invalid for security attributes applied to an assembly", c.GetSignatureForError ()); break; default: Report.Error (7051, c.Location, "SecurityAction value `{0}' is invalid for security attributes applied to a type or a method", c.GetSignatureForError ()); break; } return false; } SecurityAction? GetSecurityActionValue (ref Constant value) { if (pos_args == null) { var predefined = context.Module.PredefinedAttributes; // // BCL defines System.Security.Permissions.HostProtectionAttribute with parameterless // contructor which should not be valid but it's already part of the framework // if (Type == predefined.HostProtection.TypeSpec) { value = new IntConstant (context.Module.Compiler.BuiltinTypes, (int)SecurityAction.LinkDemand, loc); return SecurityAction.LinkDemand; } return null; } value = (Constant) pos_args [0].Expr; return (SecurityAction) value.GetValue (); } /// /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table. /// /// public void ExtractSecurityPermissionSet (MethodSpec ctor, ref SecurityType permissions) { #if STATIC object[] values; if (pos_args != null) { values = new object[pos_args.Count]; for (int i = 0; i < values.Length; ++i) values[i] = ((Constant) pos_args[i].Expr).GetValue (); } else { values = null; } PropertyInfo[] prop; object[] prop_values; if (named_values == null) { prop = null; prop_values = null; } else { prop = new PropertyInfo[named_values.Count]; prop_values = new object [named_values.Count]; for (int i = 0; i < prop.Length; ++i) { prop [i] = ((PropertyExpr) named_values [i].Key).PropertyInfo.MetaInfo; prop_values [i] = ((Constant) named_values [i].Value.Expr).GetValue (); } } if (permissions == null) permissions = new SecurityType (); var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), values, prop, prop_values); permissions.Add (cab); #else throw new NotSupportedException (); #endif } public Constant GetNamedValue (string name) { if (named_values == null) return null; for (int i = 0; i < named_values.Count; ++i) { if (named_values [i].Value.Name == name) return named_values [i].Value.Expr as Constant; } return null; } public CharSet GetCharSetValue () { return (CharSet) System.Enum.Parse (typeof (CharSet), ((Constant) pos_args[0].Expr).GetValue ().ToString ()); } public bool HasField (string fieldName) { if (named_values == null) return false; foreach (var na in named_values) { if (na.Value.Name == fieldName) return true; } return false; } // // Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value // public bool IsInternalCall () { return (GetMethodImplOptions () & MethodImplOptions.InternalCall) != 0; } public MethodImplOptions GetMethodImplOptions () { MethodImplOptions options = 0; if (pos_args.Count == 1) { options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), ((Constant) pos_args[0].Expr).GetValue ().ToString ()); } else if (HasField ("Value")) { var named = GetNamedValue ("Value"); options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ()); } return options; } // // Returns true for StructLayoutAttribute with LayoutKind.Explicit value // public bool IsExplicitLayoutKind () { if (pos_args == null || pos_args.Count != 1) return false; var value = (LayoutKind) System.Enum.Parse (typeof (LayoutKind), ((Constant) pos_args[0].Expr).GetValue ().ToString ()); return value == LayoutKind.Explicit; } public Expression GetParameterDefaultValue () { if (pos_args == null) return null; return pos_args[0].Expr; } public override bool Equals (object obj) { Attribute a = obj as Attribute; if (a == null) return false; return Type == a.Type && Target == a.Target; } public override int GetHashCode () { return Type.GetHashCode () ^ Target.GetHashCode (); } /// /// Emit attribute for Attributable symbol /// public void Emit (Dictionary> allEmitted) { var ctor = Resolve (); if (ctor == null) return; var predefined = context.Module.PredefinedAttributes; AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage); if ((usage_attr.ValidOn & Target) == 0) { Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " + "It is valid on `{1}' declarations only", GetSignatureForError (), GetValidTargets ()); return; } byte[] cdata; if (pos_args == null && named_values == null) { cdata = AttributeEncoder.Empty; } else { AttributeEncoder encoder = new AttributeEncoder (); if (pos_args != null) { var param_types = ctor.Parameters.Types; for (int j = 0; j < pos_args.Count; ++j) { var pt = param_types[j]; var arg_expr = pos_args[j].Expr; if (j == 0) { if ((Type == predefined.IndexerName || Type == predefined.Conditional) && arg_expr is Constant) { string v = ((Constant) arg_expr).GetValue () as string; if (!Tokenizer.IsValidIdentifier (v) || (Type == predefined.IndexerName && Tokenizer.IsKeyword (v))) { context.Module.Compiler.Report.Error (633, arg_expr.Location, "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ()); return; } } else if (Type == predefined.Guid) { string v = ((StringConstant) arg_expr).Value; try { new Guid (v); } catch { Error_InvalidArgumentValue (Type); return; } } else if (Type == predefined.AttributeUsage) { int v = ((IntConstant) ((EnumConstant) arg_expr).Child).Value; if (v == 0) Error_InvalidArgumentValue (Type); } else if (Type == predefined.MarshalAs) { if (pos_args.Count == 1) { var u_type = (UnmanagedType) System.Enum.Parse (typeof (UnmanagedType), ((Constant) pos_args[0].Expr).GetValue ().ToString ()); if (u_type == UnmanagedType.ByValArray && !(Owner is FieldBase)) { Report.Error (7055, pos_args [0].Expr.Location, "Unmanaged type `ByValArray' is only valid for fields"); } } } else if (Type == predefined.DllImport) { if (pos_args.Count == 1 && pos_args[0].Expr is Constant) { var value = ((Constant) pos_args[0].Expr).GetValue () as string; if (string.IsNullOrEmpty (value)) Error_InvalidArgumentValue (Type); } } else if (Type == predefined.MethodImpl) { if (pos_args.Count == 1) { var value = (int) ((Constant) arg_expr).GetValueAsLong (); if (!IsValidMethodImplOption (value)) { Error_InvalidArgumentValue (Type); } } } } arg_expr.EncodeAttributeValue (context, encoder, pt, pt); } } if (named_values != null) { encoder.Encode ((ushort) named_values.Count); foreach (var na in named_values) { if (na.Key is FieldExpr) encoder.Encode ((byte) 0x53); else encoder.Encode ((byte) 0x54); encoder.Encode (na.Key.Type); encoder.Encode (na.Value.Name); na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type, na.Key.Type); } } else { encoder.EncodeEmptyNamedArguments (); } cdata = encoder.ToArray (); } if (!IsConditionallyExcluded (ctor.DeclaringType)) { try { foreach (Attributable target in targets) target.ApplyAttributeBuilder (this, ctor, cdata, predefined); } catch (Exception e) { if (e is BadImageFormat && Report.Errors > 0) return; Error_AttributeEmitError (e.Message); return; } } if (!usage_attr.AllowMultiple && allEmitted != null) { if (allEmitted.ContainsKey (this)) { var a = allEmitted [this]; if (a == null) { a = new List (2); allEmitted [this] = a; } a.Add (this); } else { allEmitted.Add (this, null); } } if (!context.Module.Compiler.Settings.VerifyClsCompliance) return; // Here we are testing attribute arguments for array usage (error 3016) if (Owner.IsClsComplianceRequired ()) { if (pos_args != null) pos_args.CheckArrayAsAttribute (context.Module.Compiler); if (NamedArguments == null) return; NamedArguments.CheckArrayAsAttribute (context.Module.Compiler); } } bool IsConditionallyExcluded (TypeSpec type) { do { if (type.IsConditionallyExcluded (context)) return true; type = type.BaseType; } while (type != null); return false; } private Expression GetValue () { if (pos_args == null || pos_args.Count < 1) return null; return pos_args[0].Expr; } public string GetString () { Expression e = GetValue (); if (e is StringConstant) return ((StringConstant)e).Value; return null; } public bool GetBoolean () { Expression e = GetValue (); if (e is BoolConstant) return ((BoolConstant)e).Value; return false; } public TypeSpec GetArgumentType () { TypeOf e = GetValue () as TypeOf; if (e == null) return null; return e.TypeArgument; } } public class Attributes { public readonly List Attrs; public Attributes (Attribute a) { Attrs = new List (); Attrs.Add (a); } public Attributes (List attrs) { Attrs = attrs ?? new List (); } public void AddAttribute (Attribute attr) { Attrs.Add (attr); } public void AddAttributes (List attrs) { Attrs.AddRange (attrs); } public static void AttachFromPartial (Attributable target, Attributable partialSrc) { if (target.OptAttributes == null) { target.OptAttributes = partialSrc.OptAttributes; } else { target.OptAttributes.Attrs.AddRange (partialSrc.OptAttributes.Attrs); } foreach (var attr in partialSrc.OptAttributes.Attrs) { attr.SetOwner (target); } } public void AttachTo (Attributable attributable, IMemberContext context) { foreach (Attribute a in Attrs) a.AttachTo (attributable, context); } public Attributes Clone () { var al = new List (Attrs.Count); foreach (Attribute a in Attrs) al.Add (a.Clone ()); return new Attributes (al); } /// /// Checks whether attribute target is valid for the current element /// public bool CheckTargets () { for (int i = 0; i < Attrs.Count; ++i) { if (!Attrs [i].CheckTarget ()) Attrs.RemoveAt (i--); } return true; } public void ConvertGlobalAttributes (TypeContainer member, NamespaceContainer currentNamespace, bool isGlobal) { var member_explicit_targets = member.ValidAttributeTargets; for (int i = 0; i < Attrs.Count; ++i) { var attr = Attrs[0]; if (attr.ExplicitTarget == null) continue; int ii; for (ii = 0; ii < member_explicit_targets.Length; ++ii) { if (attr.ExplicitTarget == member_explicit_targets[ii]) { ii = -1; break; } } if (ii < 0 || !isGlobal) continue; member.Module.AddAttribute (attr, currentNamespace); Attrs.RemoveAt (i); --i; } } public bool HasResolveError() { foreach (var a in Attrs) { if (a.ResolveError) return true; } return false; } public Attribute Search (PredefinedAttribute t) { return Search (null, t); } public Attribute Search (string explicitTarget, PredefinedAttribute t) { foreach (Attribute a in Attrs) { if (explicitTarget != null && a.ExplicitTarget != explicitTarget) continue; if (a.ResolveTypeForComparison () == t) return a; } return null; } /// /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true /// public Attribute[] SearchMulti (PredefinedAttribute t) { List ar = null; foreach (Attribute a in Attrs) { if (a.ResolveTypeForComparison () == t) { if (ar == null) ar = new List (Attrs.Count); ar.Add (a); } } return ar == null ? null : ar.ToArray (); } public void Emit () { CheckTargets (); Dictionary> ld = Attrs.Count > 1 ? new Dictionary> () : null; foreach (Attribute a in Attrs) a.Emit (ld); if (ld == null || ld.Count == 0) return; foreach (var d in ld) { if (d.Value == null) continue; Attribute a = d.Key; foreach (Attribute collision in d.Value) a.Report.SymbolRelatedToPreviousError (collision.Location, ""); a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times", a.GetSignatureForError ()); } } public bool Contains (PredefinedAttribute t) { return Search (t) != null; } } public sealed class AttributeEncoder { [Flags] public enum EncodedTypeProperties { None = 0, DynamicType = 1, TypeParameter = 1 << 1 } public static readonly byte[] Empty; byte[] buffer; int pos; const ushort Version = 1; static AttributeEncoder () { Empty = new byte[4]; Empty[0] = (byte) Version; } public AttributeEncoder () { buffer = new byte[32]; Encode (Version); } public void Encode (bool value) { Encode (value ? (byte) 1 : (byte) 0); } public void Encode (byte value) { if (pos == buffer.Length) Grow (1); buffer [pos++] = value; } public void Encode (sbyte value) { Encode ((byte) value); } public void Encode (short value) { if (pos + 2 > buffer.Length) Grow (2); buffer[pos++] = (byte) value; buffer[pos++] = (byte) (value >> 8); } public void Encode (ushort value) { Encode ((short) value); } public void Encode (int value) { if (pos + 4 > buffer.Length) Grow (4); buffer[pos++] = (byte) value; buffer[pos++] = (byte) (value >> 8); buffer[pos++] = (byte) (value >> 16); buffer[pos++] = (byte) (value >> 24); } public void Encode (uint value) { Encode ((int) value); } public void Encode (long value) { if (pos + 8 > buffer.Length) Grow (8); buffer[pos++] = (byte) value; buffer[pos++] = (byte) (value >> 8); buffer[pos++] = (byte) (value >> 16); buffer[pos++] = (byte) (value >> 24); buffer[pos++] = (byte) (value >> 32); buffer[pos++] = (byte) (value >> 40); buffer[pos++] = (byte) (value >> 48); buffer[pos++] = (byte) (value >> 56); } public void Encode (ulong value) { Encode ((long) value); } public void Encode (float value) { Encode (SingleConverter.SingleToInt32Bits (value)); } public void Encode (double value) { Encode (BitConverter.DoubleToInt64Bits (value)); } public void Encode (string value) { if (value == null) { Encode ((byte) 0xFF); return; } var buf = Encoding.UTF8.GetBytes(value); WriteCompressedValue (buf.Length); if (pos + buf.Length > buffer.Length) Grow (buf.Length); Buffer.BlockCopy (buf, 0, buffer, pos, buf.Length); pos += buf.Length; } public EncodedTypeProperties Encode (TypeSpec type) { switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Bool: Encode ((byte) 0x02); break; case BuiltinTypeSpec.Type.Char: Encode ((byte) 0x03); break; case BuiltinTypeSpec.Type.SByte: Encode ((byte) 0x04); break; case BuiltinTypeSpec.Type.Byte: Encode ((byte) 0x05); break; case BuiltinTypeSpec.Type.Short: Encode ((byte) 0x06); break; case BuiltinTypeSpec.Type.UShort: Encode ((byte) 0x07); break; case BuiltinTypeSpec.Type.Int: Encode ((byte) 0x08); break; case BuiltinTypeSpec.Type.UInt: Encode ((byte) 0x09); break; case BuiltinTypeSpec.Type.Long: Encode ((byte) 0x0A); break; case BuiltinTypeSpec.Type.ULong: Encode ((byte) 0x0B); break; case BuiltinTypeSpec.Type.Float: Encode ((byte) 0x0C); break; case BuiltinTypeSpec.Type.Double: Encode ((byte) 0x0D); break; case BuiltinTypeSpec.Type.String: Encode ((byte) 0x0E); break; case BuiltinTypeSpec.Type.Type: Encode ((byte) 0x50); break; case BuiltinTypeSpec.Type.Object: Encode ((byte) 0x51); break; case BuiltinTypeSpec.Type.Dynamic: Encode ((byte) 0x51); return EncodedTypeProperties.DynamicType; default: if (type.IsArray) { Encode ((byte) 0x1D); return Encode (TypeManager.GetElementType (type)); } if (type.Kind == MemberKind.Enum) { Encode ((byte) 0x55); EncodeTypeName (type); } break; } return EncodedTypeProperties.None; } public void EncodeTypeName (TypeSpec type) { var old_type = type.GetMetaInfo (); Encode (type.MemberDefinition.IsImported ? old_type.AssemblyQualifiedName : old_type.FullName); } public void EncodeTypeName (TypeContainer type) { Encode (type.GetSignatureForMetadata ()); } // // Encodes single property named argument per call // public void EncodeNamedPropertyArgument (PropertySpec property, Constant value) { Encode ((ushort) 1); // length Encode ((byte) 0x54); // property Encode (property.MemberType); Encode (property.Name); value.EncodeAttributeValue (null, this, property.MemberType, property.MemberType); } // // Encodes single field named argument per call // public void EncodeNamedFieldArgument (FieldSpec field, Constant value) { Encode ((ushort) 1); // length Encode ((byte) 0x53); // field Encode (field.MemberType); Encode (field.Name); value.EncodeAttributeValue (null, this, field.MemberType, field.MemberType); } public void EncodeNamedArguments (T[] members, Constant[] values) where T : MemberSpec, IInterfaceMemberSpec { Encode ((ushort) members.Length); for (int i = 0; i < members.Length; ++i) { var member = members[i]; if (member.Kind == MemberKind.Field) Encode ((byte) 0x53); else if (member.Kind == MemberKind.Property) Encode ((byte) 0x54); else throw new NotImplementedException (member.Kind.ToString ()); Encode (member.MemberType); Encode (member.Name); values [i].EncodeAttributeValue (null, this, member.MemberType, member.MemberType); } } public void EncodeEmptyNamedArguments () { Encode ((ushort) 0); } void Grow (int inc) { int size = System.Math.Max (pos * 4, pos + inc + 2); Array.Resize (ref buffer, size); } void WriteCompressedValue (int value) { if (value < 0x80) { Encode ((byte) value); return; } if (value < 0x4000) { Encode ((byte) (0x80 | (value >> 8))); Encode ((byte) value); return; } Encode (value); } public byte[] ToArray () { byte[] buf = new byte[pos]; Array.Copy (buffer, buf, pos); return buf; } } /// /// Helper class for attribute verification routine. /// static class AttributeTester { /// /// Common method for Obsolete error/warning reporting. /// public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report) { if (oa.IsError) { Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message); return; } if (oa.Message == null || oa.Message.Length == 0) { Report.Warning (612, 1, loc, "`{0}' is obsolete", member); return; } Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message); } } // // Predefined attribute types // public class PredefinedAttributes { // Build-in attributes public readonly PredefinedAttribute ParamArray; public readonly PredefinedAttribute Out; // Optional attributes public readonly PredefinedAttribute Obsolete; public readonly PredefinedAttribute DllImport; public readonly PredefinedAttribute MethodImpl; public readonly PredefinedAttribute MarshalAs; public readonly PredefinedAttribute In; public readonly PredefinedAttribute IndexerName; public readonly PredefinedAttribute Conditional; public readonly PredefinedAttribute CLSCompliant; public readonly PredefinedAttribute Security; public readonly PredefinedAttribute Required; public readonly PredefinedAttribute Guid; public readonly PredefinedAttribute AssemblyCulture; public readonly PredefinedAttribute AssemblyVersion; public readonly PredefinedAttribute AssemblyAlgorithmId; public readonly PredefinedAttribute AssemblyFlags; public readonly PredefinedAttribute AssemblyFileVersion; public readonly PredefinedAttribute AssemblyInformationalVersion; public readonly PredefinedAttribute ComImport; public readonly PredefinedAttribute CoClass; public readonly PredefinedAttribute AttributeUsage; public readonly PredefinedAttribute DefaultParameterValue; public readonly PredefinedAttribute OptionalParameter; public readonly PredefinedAttribute UnverifiableCode; public readonly PredefinedAttribute DefaultCharset; public readonly PredefinedAttribute TypeForwarder; public readonly PredefinedAttribute FixedBuffer; public readonly PredefinedAttribute CompilerGenerated; public readonly PredefinedAttribute InternalsVisibleTo; public readonly PredefinedAttribute RuntimeCompatibility; public readonly PredefinedAttribute DebuggerHidden; public readonly PredefinedAttribute UnsafeValueType; public readonly PredefinedAttribute UnmanagedFunctionPointer; public readonly PredefinedDebuggerBrowsableAttribute DebuggerBrowsable; public readonly PredefinedAttribute DebuggerStepThrough; public readonly PredefinedDebuggableAttribute Debuggable; public readonly PredefinedAttribute HostProtection; // New in .NET 3.5 public readonly PredefinedAttribute Extension; // New in .NET 4.0 public readonly PredefinedDynamicAttribute Dynamic; // New in .NET 4.5 public readonly PredefinedStateMachineAttribute AsyncStateMachine; // // Optional types which are used as types and for member lookup // public readonly PredefinedAttribute DefaultMember; public readonly PredefinedDecimalAttribute DecimalConstant; public readonly PredefinedAttribute StructLayout; public readonly PredefinedAttribute FieldOffset; public readonly PredefinedAttribute AssemblyProduct; public readonly PredefinedAttribute AssemblyCompany; public readonly PredefinedAttribute AssemblyCopyright; public readonly PredefinedAttribute AssemblyTrademark; public readonly PredefinedAttribute CallerMemberNameAttribute; public readonly PredefinedAttribute CallerLineNumberAttribute; public readonly PredefinedAttribute CallerFilePathAttribute; public PredefinedAttributes (ModuleContainer module) { ParamArray = new PredefinedAttribute (module, "System", "ParamArrayAttribute"); Out = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OutAttribute"); ParamArray.Resolve (); Out.Resolve (); Obsolete = new PredefinedAttribute (module, "System", "ObsoleteAttribute"); DllImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DllImportAttribute"); MethodImpl = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "MethodImplAttribute"); MarshalAs = new PredefinedAttribute (module, "System.Runtime.InteropServices", "MarshalAsAttribute"); In = new PredefinedAttribute (module, "System.Runtime.InteropServices", "InAttribute"); IndexerName = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IndexerNameAttribute"); Conditional = new PredefinedAttribute (module, "System.Diagnostics", "ConditionalAttribute"); CLSCompliant = new PredefinedAttribute (module, "System", "CLSCompliantAttribute"); Security = new PredefinedAttribute (module, "System.Security.Permissions", "SecurityAttribute"); Required = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RequiredAttributeAttribute"); Guid = new PredefinedAttribute (module, "System.Runtime.InteropServices", "GuidAttribute"); AssemblyCulture = new PredefinedAttribute (module, "System.Reflection", "AssemblyCultureAttribute"); AssemblyVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyVersionAttribute"); AssemblyAlgorithmId = new PredefinedAttribute (module, "System.Reflection", "AssemblyAlgorithmIdAttribute"); AssemblyFlags = new PredefinedAttribute (module, "System.Reflection", "AssemblyFlagsAttribute"); AssemblyFileVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyFileVersionAttribute"); ComImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "ComImportAttribute"); CoClass = new PredefinedAttribute (module, "System.Runtime.InteropServices", "CoClassAttribute"); AttributeUsage = new PredefinedAttribute (module, "System", "AttributeUsageAttribute"); DefaultParameterValue = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultParameterValueAttribute"); OptionalParameter = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OptionalAttribute"); UnverifiableCode = new PredefinedAttribute (module, "System.Security", "UnverifiableCodeAttribute"); HostProtection = new PredefinedAttribute (module, "System.Security.Permissions", "HostProtectionAttribute"); DefaultCharset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultCharSetAttribute"); TypeForwarder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "TypeForwardedToAttribute"); FixedBuffer = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "FixedBufferAttribute"); CompilerGenerated = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"); InternalsVisibleTo = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute"); RuntimeCompatibility = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute"); DebuggerHidden = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerHiddenAttribute"); UnsafeValueType = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "UnsafeValueTypeAttribute"); UnmanagedFunctionPointer = new PredefinedAttribute (module, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"); DebuggerBrowsable = new PredefinedDebuggerBrowsableAttribute (module, "System.Diagnostics", "DebuggerBrowsableAttribute"); DebuggerStepThrough = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerStepThroughAttribute"); Debuggable = new PredefinedDebuggableAttribute (module, "System.Diagnostics", "DebuggableAttribute"); Extension = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "ExtensionAttribute"); Dynamic = new PredefinedDynamicAttribute (module, "System.Runtime.CompilerServices", "DynamicAttribute"); DefaultMember = new PredefinedAttribute (module, "System.Reflection", "DefaultMemberAttribute"); DecimalConstant = new PredefinedDecimalAttribute (module, "System.Runtime.CompilerServices", "DecimalConstantAttribute"); StructLayout = new PredefinedAttribute (module, "System.Runtime.InteropServices", "StructLayoutAttribute"); FieldOffset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "FieldOffsetAttribute"); AssemblyProduct = new PredefinedAttribute (module, "System.Reflection", "AssemblyProductAttribute"); AssemblyCompany = new PredefinedAttribute (module, "System.Reflection", "AssemblyCompanyAttribute"); AssemblyCopyright = new PredefinedAttribute (module, "System.Reflection", "AssemblyCopyrightAttribute"); AssemblyTrademark = new PredefinedAttribute (module, "System.Reflection", "AssemblyTrademarkAttribute"); AssemblyInformationalVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyInformationalVersionAttribute"); AsyncStateMachine = new PredefinedStateMachineAttribute (module, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute"); CallerMemberNameAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerMemberNameAttribute"); CallerLineNumberAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerLineNumberAttribute"); CallerFilePathAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerFilePathAttribute"); // TODO: Should define only attributes which are used for comparison const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly; foreach (var fi in GetType ().GetFields (all_fields)) { ((PredefinedAttribute) fi.GetValue (this)).Define (); } } } public class PredefinedAttribute : PredefinedType { protected MethodSpec ctor; public PredefinedAttribute (ModuleContainer module, string ns, string name) : base (module, MemberKind.Class, ns, name) { } #region Properties public MethodSpec Constructor { get { return ctor; } } #endregion public static bool operator == (TypeSpec type, PredefinedAttribute pa) { return type == pa.type && pa.type != null; } public static bool operator != (TypeSpec type, PredefinedAttribute pa) { return type != pa.type; } public override int GetHashCode () { return base.GetHashCode (); } public override bool Equals (object obj) { throw new NotSupportedException (); } public void EmitAttribute (ConstructorBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (MethodBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (PropertyBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (FieldBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (TypeBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (AssemblyBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (ModuleBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } public void EmitAttribute (ParameterBuilder builder) { if (ResolveBuilder ()) builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty); } ConstructorInfo GetCtorMetaInfo () { return (ConstructorInfo) ctor.GetMetaInfo (); } public bool ResolveBuilder () { if (ctor != null) return true; // // Handle all parameter-less attributes as optional // if (!Define ()) return false; ctor = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (ParametersCompiled.EmptyReadOnlyParameters), BindingRestriction.DeclaredOnly); return ctor != null; } } public class PredefinedDebuggerBrowsableAttribute : PredefinedAttribute { public PredefinedDebuggerBrowsableAttribute (ModuleContainer module, string ns, string name) : base (module, ns, name) { } public void EmitAttribute (FieldBuilder builder, System.Diagnostics.DebuggerBrowsableState state) { var ctor = module.PredefinedMembers.DebuggerBrowsableAttributeCtor.Get (); if (ctor == null) return; AttributeEncoder encoder = new AttributeEncoder (); encoder.Encode ((int) state); encoder.EncodeEmptyNamedArguments (); builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); } } public class PredefinedDebuggableAttribute : PredefinedAttribute { public PredefinedDebuggableAttribute (ModuleContainer module, string ns, string name) : base (module, ns, name) { } public void EmitAttribute (AssemblyBuilder builder, System.Diagnostics.DebuggableAttribute.DebuggingModes modes) { var atype = module.PredefinedAttributes.Debuggable; if (!atype.Define ()) return; MethodSpec ctor = null; foreach (MethodSpec m in MemberCache.FindMembers (atype.TypeSpec, CSharp.Constructor.ConstructorName, true)) { if (m.Parameters.Count != 1) continue; if (m.Parameters.Types[0].Kind == MemberKind.Enum) { ctor = m; } } if (ctor == null) return; AttributeEncoder encoder = new AttributeEncoder (); encoder.Encode ((int) modes); encoder.EncodeEmptyNamedArguments (); builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); } } public class PredefinedDecimalAttribute : PredefinedAttribute { public PredefinedDecimalAttribute (ModuleContainer module, string ns, string name) : base (module, ns, name) { } public void EmitAttribute (ParameterBuilder builder, decimal value, Location loc) { var ctor = module.PredefinedMembers.DecimalConstantAttributeCtor.Resolve (loc); if (ctor == null) return; int[] bits = decimal.GetBits (value); AttributeEncoder encoder = new AttributeEncoder (); encoder.Encode ((byte) (bits[3] >> 16)); encoder.Encode ((byte) (bits[3] >> 31)); encoder.Encode ((uint) bits[2]); encoder.Encode ((uint) bits[1]); encoder.Encode ((uint) bits[0]); encoder.EncodeEmptyNamedArguments (); builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); } public void EmitAttribute (FieldBuilder builder, decimal value, Location loc) { var ctor = module.PredefinedMembers.DecimalConstantAttributeCtor.Resolve (loc); if (ctor == null) return; int[] bits = decimal.GetBits (value); AttributeEncoder encoder = new AttributeEncoder (); encoder.Encode ((byte) ((bits[3] & 0xFF0000) >> 16)); // Scale encoder.Encode ((byte) ((bits[3] >> 31) << 7)); // Sign encoded as 0x80 for negative, 0x0 for possitive encoder.Encode ((uint) bits[2]); encoder.Encode ((uint) bits[1]); encoder.Encode ((uint) bits[0]); encoder.EncodeEmptyNamedArguments (); builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); } } public class PredefinedStateMachineAttribute : PredefinedAttribute { public PredefinedStateMachineAttribute (ModuleContainer module, string ns, string name) : base (module, ns, name) { } public void EmitAttribute (MethodBuilder builder, StateMachine type) { var predefined_ctor = module.PredefinedMembers.AsyncStateMachineAttributeCtor; var ctor = predefined_ctor.Get (); if (ctor == null) return; AttributeEncoder encoder = new AttributeEncoder (); encoder.EncodeTypeName (type); encoder.EncodeEmptyNamedArguments (); builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); } } public class PredefinedDynamicAttribute : PredefinedAttribute { MethodSpec tctor; public PredefinedDynamicAttribute (ModuleContainer module, string ns, string name) : base (module, ns, name) { } public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc) { if (ResolveTransformationCtor (loc)) { var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) }); builder.SetCustomAttribute (cab); } } public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc) { if (ResolveTransformationCtor (loc)) { var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) }); builder.SetCustomAttribute (cab); } } public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc) { if (ResolveTransformationCtor (loc)) { var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) }); builder.SetCustomAttribute (cab); } } public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc) { if (ResolveTransformationCtor (loc)) { var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) }); builder.SetCustomAttribute (cab); } } // // When any element of the type is a dynamic type // // This method builds a transformation array for dynamic types // used in places where DynamicAttribute cannot be applied to. // It uses bool flag when type is of dynamic type and each // section always starts with "false" for some reason. // // LAMESPEC: This should be part of C# specification // // Example: Func // Transformation: { false, true, false, false, true } // static bool[] GetTransformationFlags (TypeSpec t) { bool[] element; var ac = t as ArrayContainer; if (ac != null) { element = GetTransformationFlags (ac.Element); if (element == null) return new bool[] { false, false }; bool[] res = new bool[element.Length + 1]; res[0] = false; Array.Copy (element, 0, res, 1, element.Length); return res; } if (t == null) return null; if (t.IsGeneric) { List transform = null; var targs = t.TypeArguments; for (int i = 0; i < targs.Length; ++i) { element = GetTransformationFlags (targs[i]); if (element != null) { if (transform == null) { transform = new List (); for (int ii = 0; ii <= i; ++ii) transform.Add (false); } transform.AddRange (element); } else if (transform != null) { transform.Add (false); } } if (transform != null) return transform.ToArray (); } if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) return new bool[] { true }; return null; } bool ResolveTransformationCtor (Location loc) { if (tctor != null) return true; tctor = module.PredefinedMembers.DynamicAttributeCtor.Resolve (loc); return tctor != null; } } }