2004-12-22 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / mcs / attribute.cs
index b59e70a776dc65e694e5f2cf039c8a617191b2ef..51de7ad253295cced2fd2671c83a9d2deed1796a 100644 (file)
@@ -2,6 +2,7 @@
 // attribute.cs: Attribute Handler
 //
 // Author: Ravi Pratap (ravi@ximian.com)
+//         Marek Safar (marek.safar@seznam.cz)
 //
 // Licensed under the terms of the GNU GPL
 //
 using System;
 using System.Diagnostics;
 using System.Collections;
+using System.Collections.Specialized;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
+using System.Security; 
+using System.Security.Permissions;
 using System.Text;
 
 namespace Mono.CSharp {
 
+       /// <summary>
+       ///   Base class for objects that can have Attributes applied to them.
+       /// </summary>
+       public abstract class Attributable {
+               /// <summary>
+               ///   Attributes for this type
+               /// </summary>
+               Attributes attributes;
+
+               public Attributable (Attributes attrs)
+               {
+                       attributes = attrs;
+               }
+
+               public Attributes OptAttributes 
+               {
+                       get {
+                               return attributes;
+                       }
+                       set {
+                               attributes = value;
+                       }
+               }
+
+               /// <summary>
+               /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
+               /// </summary>
+               public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
+
+               /// <summary>
+               /// Returns one AttributeTarget for this element.
+               /// </summary>
+               public abstract AttributeTargets AttributeTargets { get; }
+
+               public abstract bool IsClsCompliaceRequired (DeclSpace ds);
+
+               /// <summary>
+               /// Gets list of valid attribute targets for explicit target declaration.
+               /// The first array item is default target. Don't break this rule.
+               /// </summary>
+               public abstract string[] ValidAttributeTargets { get; }
+       };
+
        public class Attribute {
+               public readonly string ExplicitTarget;
+               public AttributeTargets Target;
+
                public readonly string    Name;
                public readonly ArrayList Arguments;
 
-               Location Location;
+               public readonly Location Location;
 
                public Type Type;
-               
-               //
-               // The following are only meaningful when the attribute
-               // being emitted is an AttributeUsage attribute
-               //
-               AttributeTargets Targets;
-               bool AllowMultiple;
-               bool Inherited;
 
-               bool UsageAttr = false;
-               
+               bool resolve_error;
+
+               // Is non-null if type is AttributeUsageAttribute
+               AttributeUsageAttribute usage_attribute;
+
+               public AttributeUsageAttribute UsageAttribute {
+                       get {
+                               return usage_attribute;
+                       }
+               }
+
                MethodImplOptions ImplOptions;
                UnmanagedType     UnmanagedType;
                CustomAttributeBuilder cb;
@@ -47,20 +98,23 @@ namespace Mono.CSharp {
                FieldInfo [] field_info_arr;
                object [] field_values_arr;
                object [] prop_values_arr;
+               object [] pos_values;
+
+               static PtrHashtable usage_attr_cache = new PtrHashtable ();
                
-               public Attribute (string name, ArrayList args, Location loc)
+               public Attribute (string target, string name, ArrayList args, Location loc)
                {
                        Name = name;
                        Arguments = args;
                        Location = loc;
+                       ExplicitTarget = target;
                }
 
                void Error_InvalidNamedArgument (string name)
                {
-                       Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
-                                     "argument. Named attribute arguments must be fields which are not " +
-                                     "readonly, static or const, or properties with a set accessor which "+
-                                     "are not static.");
+                       Report.Error (617, Location, "Invalid attribute argument: '{0}'.  Argument must be fields " +
+                                     "fields which are not readonly, static or const;  or read-write instance properties.",
+                                     Name);
                }
 
                static void Error_AttributeArgumentNotValid (Location loc)
@@ -70,47 +124,82 @@ namespace Mono.CSharp {
                                      "expression or array creation expression");
                }
 
-               static void Error_AttributeConstructorMismatch (Location loc)
+               /// <summary>
+               /// This is rather hack. We report many emit attribute error with same error to be compatible with
+               /// csc. But because csc has to report them this way because error came from ilasm we needn't.
+               /// </summary>
+               public void Error_AttributeEmitError (string inner)
+               {
+                       Report.Error (647, Location, "Error emitting '{0}' attribute because '{1}'", Name, inner);
+               }
+
+               public void Error_InvalidSecurityParent ()
+               {
+                       Error_AttributeEmitError ("it is attached to invalid parent");
+               }
+
+               void Error_AttributeConstructorMismatch ()
                {
-                       Report.Error (-6, loc,
+                       Report.Error (-6, Location,
                                       "Could not find a constructor for this argument list.");
                }
 
                /// <summary>
-                ///   Tries to resolve the type of the attribute. Flags an error if it can't.
+                ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
                 /// </summary>
-               private Type CheckAttributeType (EmitContext ec) {
-                       Type t;
-                       bool isattributeclass = true;
-
-                       t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
-                       if (t != null) {
-                               isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
-                               if (isattributeclass)
-                                       return t;
+               protected virtual Type CheckAttributeType (EmitContext ec)
+               {
+                       string NameAttribute = Name + "Attribute";
+
+                       Type t1 = ec.ResolvingTypeTree
+                               ? ec.DeclSpace.FindType (Location, Name)
+                               : RootContext.LookupType (ec.DeclSpace, Name, true, Location);
+
+                       // FIXME: Shouldn't do this for quoted attributes: [@A]
+                       Type t2 = ec.ResolvingTypeTree
+                               ? ec.DeclSpace.FindType (Location, NameAttribute)
+                               : RootContext.LookupType (ec.DeclSpace, NameAttribute, true, Location);
+
+                       String err0616 = null;
+
+                       if (t1 != null && ! t1.IsSubclassOf (TypeManager.attribute_type)) {
+                               t1 = null;
+                               err0616 = "'" + Name + "': is not an attribute class";
                        }
-                       t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
-                       if (t != null) {
-                               if (t.IsSubclassOf (TypeManager.attribute_type))
-                                       return t;
+                       if (t2 != null && ! t2.IsSubclassOf (TypeManager.attribute_type)) {
+                               t2 = null;
+                               err0616 = (err0616 != null) 
+                                       ? "Neither '" + Name + "' nor '" + NameAttribute +"' is an attribute class"
+                                       : "'" + Name + "Attribute': is not an attribute class";
                        }
-                       if (!isattributeclass) {
-                               Report.Error (616, Location, "'" + Name + "': is not an attribute class");
+
+                       if (t1 != null && t2 != null) {
+                               Report.Error(1614, Location, "'" + Name + "': is ambiguous; " 
+                                            + " use either '@" + Name + "' or '" + NameAttribute + "'");
                                return null;
                        }
-                       if (t != null) {
-                               Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
+                       if (t1 != null)
+                               return t1;
+                       if (t2 != null)
+                               return t2;
+
+                       if (err0616 != null) {
+                               Report.Error (616, Location, err0616);
                                return null;
                        }
-                       Report.Error (
-                               246, Location, "Could not find attribute '" + Name + "' (are you" +
-                               " missing a using directive or an assembly reference ?)");
+
+                       Report.Error (246, Location, 
+                                     "Could not find attribute '" + Name 
+                                     + "' (are you missing a using directive or an assembly reference ?)");
+
+                       resolve_error = true;
                        return null;
                }
 
                public Type ResolveType (EmitContext ec)
                {
-                       Type = CheckAttributeType (ec);
+                       if (Type == null)
+                               Type = CheckAttributeType (ec);
                        return Type;
                }
 
@@ -128,14 +217,37 @@ namespace Mono.CSharp {
                        }
                }
 
+               string GetFullMemberName (string member)
+               {
+                       return Type.FullName + '.' + member;
+               }
+
                //
                // Given an expression, if the expression is a valid attribute-argument-expression
                // returns an object that can be used to encode it, or null on failure.
                //
-               public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)
+               public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result)
                {
-                       if (e is Constant) {
-                               result = ((Constant) e).GetValue ();
+                       if (e is EnumConstant) {
+                               if (RootContext.StdLib)
+                                       result = ((EnumConstant)e).GetValueAsEnumType ();
+                               else
+                                       result = ((EnumConstant)e).GetValue ();
+
+                               return true;
+                       }
+
+                       Constant constant = e as Constant;
+                       if (constant != null) {
+                               if (e.Type != arg_type) {
+                                       constant = Const.ChangeType (loc, constant, arg_type);
+                                       if (constant == null) {
+                                               result = null;
+                                               Error_AttributeArgumentNotValid (loc);
+                                               return false;
+                                       }
+                               }
+                               result = constant.GetValue ();
                                return true;
                        } else if (e is TypeOf) {
                                result = ((TypeOf) e).TypeArg;
@@ -145,11 +257,8 @@ namespace Mono.CSharp {
                                if (result != null)
                                        return true;
                        } else if (e is EmptyCast) {
-                               result = e;
-                               if (((EmptyCast) e).Child is Constant) {
-                                       result = ((Constant) ((EmptyCast)e).Child).GetValue();
-                               }
-                               return true;
+                               Expression child = ((EmptyCast)e).Child;
+                               return GetAttributeArgumentExpression (child, loc, child.Type, out result);
                        }
 
                        result = null;
@@ -157,17 +266,36 @@ namespace Mono.CSharp {
                        return false;
                }
                
-               public CustomAttributeBuilder Resolve (EmitContext ec)
+               public virtual CustomAttributeBuilder Resolve (EmitContext ec)
                {
-                       if (Type == null)
-                               Type = CheckAttributeType (ec);
-                       if (Type == null)
+                       if (resolve_error)
+                               return null;
+
+                       resolve_error = true;
+
+                       Type oldType = Type;
+                       
+                       // Sanity check.
+                       Type = CheckAttributeType (ec);
+
+                       if (oldType == null && Type == null)
+                               return null;
+                       if (oldType != null && oldType != Type){
+                               Report.Error (-27, Location,
+                                             "Attribute {0} resolved to different types at different times: {1} vs. {2}",
+                                             Name, oldType, Type);
+                               return null;
+                       }
+
+                       if (Type.IsAbstract) {
+                               Report.Error (653, Location, "Cannot apply attribute class '{0}' because it is abstract", Name);
                                return null;
+                       }
 
                        bool MethodImplAttr = false;
                        bool MarshalAsAttr = false;
                        bool GuidAttr = false;
-                       UsageAttr = false;
+                       bool usage_attr = false;
 
                        bool DoCompares = true;
 
@@ -177,7 +305,7 @@ namespace Mono.CSharp {
                         //
                         
                        if (Type == TypeManager.attribute_usage_type)
-                               UsageAttr = true;
+                               usage_attr = true;
                        else if (Type == TypeManager.methodimpl_attr_type)
                                MethodImplAttr = true;
                        else if (Type == TypeManager.marshal_as_attr_type)
@@ -201,7 +329,7 @@ namespace Mono.CSharp {
                                        named_args = (ArrayList) Arguments [1];
                        }
 
-                       object [] pos_values = new object [pos_arg_count];
+                       pos_values = new object [pos_arg_count];
 
                        //
                        // First process positional arguments 
@@ -218,27 +346,32 @@ namespace Mono.CSharp {
                                e = a.Expr;
 
                                object val;
-                               if (!GetAttributeArgumentExpression (e, Location, out val))
+                               if (!GetAttributeArgumentExpression (e, Location, a.Type, out val))
                                        return null;
-                               
+
                                pos_values [i] = val;
+
                                if (DoCompares){
-                                       if (UsageAttr)
-                                               this.Targets = (AttributeTargets) pos_values [0];
-                                       else if (MethodImplAttr)
-                                               this.ImplOptions = (MethodImplOptions) pos_values [0];
-                                       else if (GuidAttr){
+                                       if (usage_attr) {
+                                               if ((int)val == 0) {
+                                                       Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute");
+                                                       return null;
+                                               }
+                                               usage_attribute = new AttributeUsageAttribute ((AttributeTargets)val);
+                                       } else if (MethodImplAttr) {
+                                               this.ImplOptions = (MethodImplOptions) val;
+                                       } else if (GuidAttr){
                                                //
                                                // we will later check the validity of the type
                                                //
-                                               if (pos_values [0] is string){
-                                                       if (!ValidateGuid ((string) pos_values [0]))
+                                               if (val is string){
+                                                       if (!ValidateGuid ((string) val))
                                                                return null;
                                                }
                                                
                                        } else if (MarshalAsAttr)
                                                this.UnmanagedType =
-                                               (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
+                                               (System.Runtime.InteropServices.UnmanagedType) val;
                                }
                        }
 
@@ -257,12 +390,20 @@ namespace Mono.CSharp {
                                field_values = new ArrayList ();
                                prop_values = new ArrayList ();
                        }
+
+                       Hashtable seen_names = new Hashtable();
                        
                        for (i = 0; i < named_args.Count; i++) {
                                DictionaryEntry de = (DictionaryEntry) named_args [i];
                                string member_name = (string) de.Key;
                                Argument a  = (Argument) de.Value;
                                Expression e;
+
+                               if (seen_names.Contains(member_name)) {
+                                       Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument");
+                                       return null;
+                               }                               
+                               seen_names.Add(member_name, 1);
                                
                                if (!a.Resolve (ec, Location))
                                        return null;
@@ -273,7 +414,24 @@ namespace Mono.CSharp {
                                        BindingFlags.Public | BindingFlags.Instance,
                                        Location);
 
-                               if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
+                               if (member == null) {
+                                       member = Expression.MemberLookup (ec, Type, member_name,
+                                               MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance,
+                                               Location);
+
+                                       if (member != null) {
+                                               Report.Error (122, Location, "'{0}' is inaccessible due to its protection level", GetFullMemberName (member_name));
+                                               return null;
+                                       }
+                               }
+
+                               if (member == null){
+                                       Report.Error (117, Location, "Attribute `{0}' does not contain a definition for `{1}'",
+                                                     Type, member_name);
+                                       return null;
+                               }
+                               
+                               if (!(member is PropertyExpr || member is FieldExpr)) {
                                        Error_InvalidNamedArgument (member_name);
                                        return null;
                                }
@@ -283,31 +441,24 @@ namespace Mono.CSharp {
                                        PropertyExpr pe = (PropertyExpr) member;
                                        PropertyInfo pi = pe.PropertyInfo;
 
-                                       if (!pi.CanWrite) {
+                                       if (!pi.CanWrite || !pi.CanRead) {
+                                               Report.SymbolRelatedToPreviousError (pi);
                                                Error_InvalidNamedArgument (member_name);
                                                return null;
                                        }
 
-                                       if (e is Constant) {
-                                               object o = ((Constant) e).GetValue ();
-                                               prop_values.Add (o);
-                                               
-                                               if (UsageAttr) {
-                                                       if (member_name == "AllowMultiple")
-                                                               this.AllowMultiple = (bool) o;
-                                                       if (member_name == "Inherited")
-                                                               this.Inherited = (bool) o;
-                                               }
-                                               
-                                       } else if (e is TypeOf) {
-                                               prop_values.Add (((TypeOf) e).TypeArg);
-                                       } else if (e is ArrayCreation) {
-                                               prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());
-                                       } else {
-                                               Error_AttributeArgumentNotValid (Location);
+                                       object value;
+                                       if (!GetAttributeArgumentExpression (e, Location, pi.PropertyType, out value))
                                                return null;
+
+                                       if (usage_attribute != null) {
+                                               if (member_name == "AllowMultiple")
+                                                       usage_attribute.AllowMultiple = (bool) value;
+                                               if (member_name == "Inherited")
+                                                       usage_attribute.Inherited = (bool) value;
                                        }
-                                       
+
+                                       prop_values.Add (value);
                                        prop_infos.Add (pi);
                                        
                                } else if (member is FieldExpr) {
@@ -319,20 +470,11 @@ namespace Mono.CSharp {
                                                return null;
                                        }
 
-                                       //
-                                       // Handle charset here, and set the TypeAttributes
-                                       
-                                       if (e is Constant){
-                                               object value = ((Constant) e).GetValue ();
-                                               
-                                               field_values.Add (value);
-                                       } else if (e is TypeOf) {
-                                               field_values.Add (((TypeOf) e).TypeArg);
-                                       } else {
-                                               Error_AttributeArgumentNotValid (Location);
-                                               return null;
-                                       }
-                                       
+                                       object value;
+                                       if (!GetAttributeArgumentExpression (e, Location, fi.FieldType, out value))
+                                               return null;
+
+                                       field_values.Add (value);                                       
                                        field_infos.Add (fi);
                                }
                        }
@@ -343,15 +485,14 @@ namespace Mono.CSharp {
                                 Location);
 
                        if (mg == null) {
-                               Error_AttributeConstructorMismatch (Location);
+                               Error_AttributeConstructorMismatch ();
                                return null;
                        }
 
                        MethodBase constructor = Invocation.OverloadResolve (
-                               ec, (MethodGroupExpr) mg, pos_args, Location);
+                               ec, (MethodGroupExpr) mg, pos_args, false, Location);
 
                        if (constructor == null) {
-                               Error_AttributeConstructorMismatch (Location);
                                return null;
                        }
 
@@ -363,11 +504,18 @@ namespace Mono.CSharp {
 
                        ParameterData pd = Invocation.GetParameterData (constructor);
 
-                       int group_in_params_array = Int32.MaxValue;
-                       int pc = pd.Count;
-                       if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
-                               group_in_params_array = pc-1;
-                       
+                       int last_real_param = pd.Count;
+                       if (pd.HasParams) {
+                               // When the params is not filled we need to put one
+                               if (last_real_param > pos_arg_count) {
+                                       object [] new_pos_values = new object [pos_arg_count + 1];
+                                       pos_values.CopyTo (new_pos_values, 0);
+                                       new_pos_values [pos_arg_count] = new object [] {} ;
+                                       pos_values = new_pos_values;
+                               }
+                               last_real_param--;
+                       }
+
                        for (int j = 0; j < pos_arg_count; ++j) {
                                Argument a = (Argument) pos_args [j];
                                
@@ -376,32 +524,24 @@ namespace Mono.CSharp {
                                        return null;
                                }
 
-                               if (j < group_in_params_array)
+                               if (j < last_real_param)
                                        continue;
                                
-                               if (j == group_in_params_array){
-                                       object v = pos_values [j];
-                                       int count = pos_arg_count - j;
-
-                                       object [] array = new object [count];
+                               if (j == last_real_param) {
+                                       object [] array = new object [pos_arg_count - last_real_param];
+                                       array [0] = pos_values [j];
                                        pos_values [j] = array;
-                                       array [0] = v;
-                               } else {
-                                       object [] array = (object []) pos_values [group_in_params_array];
-
-                                       array [j - group_in_params_array] = pos_values [j];
+                                       continue;
                                }
+
+                               object [] params_array = (object []) pos_values [last_real_param];
+                               params_array [j - last_real_param] = pos_values [j];
                        }
 
-                       //
                        // Adjust the size of the pos_values if it had params
-                       //
-                       if (group_in_params_array != Int32.MaxValue){
-                               int argc = group_in_params_array+1;
-                               object [] new_pos_values = new object [argc];
-
-                               for (int p = 0; p < argc; p++)
-                                       new_pos_values [p] = pos_values [p];
+                       if (last_real_param != pos_arg_count) {
+                               object [] new_pos_values = new object [last_real_param + 1];
+                               Array.Copy (pos_values, new_pos_values, last_real_param + 1);
                                pos_values = new_pos_values;
                        }
 
@@ -426,13 +566,6 @@ namespace Mono.CSharp {
                                else
                                        cb = new CustomAttributeBuilder (
                                                (ConstructorInfo) constructor, pos_values);
-                       } catch (NullReferenceException) {
-                               // 
-                               // Don't know what to do here
-                               //
-                               Report.Warning (
-                                       -101, Location, "NullReferenceException while trying to create attribute." +
-                                        "Something's wrong!");
                        } catch (Exception e) {
                                //
                                // Sample:
@@ -440,48 +573,22 @@ namespace Mono.CSharp {
                                // [DefaultValue (CollectionChangeAction.Add)]
                                // class X { static void Main () {} }
                                //
-                               Report.Warning (
-                                       -23, Location,
-                                       "The compiler can not encode this attribute in .NET due to\n" +
-                                       "\ta bug in the .NET runtime.  Try the Mono runtime.\nThe error was: " + e.Message);
+                               Error_AttributeArgumentNotValid (Location);
+                               return null;
                        }
                        
+                       resolve_error = false;
                        return cb;
                }
 
-                /// <summary>
-                ///   Get a string containing a list of valid targets for the attribute 'attr'
-                /// </summary>
-               static string GetValidTargets (Attribute attr)
+               /// <summary>
+               ///   Get a string containing a list of valid targets for the attribute 'attr'
+               /// </summary>
+               public string GetValidTargets ()
                {
                        StringBuilder sb = new StringBuilder ();
-                       AttributeTargets targets = 0;
-                       
-                       TypeContainer a = TypeManager.LookupAttr (attr.Type);
-
-                       if (a == null) {
-                               
-                               System.Attribute [] attrs = null;
-                               
-                               try {
-                                       attrs = System.Attribute.GetCustomAttributes (attr.Type);
-                                       
-                               } catch {
-                                       Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
-                                                     " (maybe you forgot to set the usage using the" +
-                                                     " AttributeUsage attribute ?).");
-                                       return null;
-                               }
-                                       
-                               foreach (System.Attribute tmp in attrs)
-                                       if (tmp is AttributeUsageAttribute) {
-                                               targets = ((AttributeUsageAttribute) tmp).ValidOn;
-                                               break;
-                                       }
-                       } else
-                               targets = a.Targets;
+                       AttributeTargets targets = GetAttributeUsage ().ValidOn;
 
-                       
                        if ((targets & AttributeTargets.Assembly) != 0)
                                sb.Append ("'assembly' ");
 
@@ -519,7 +626,7 @@ namespace Mono.CSharp {
                                sb.Append ("'property' ");
 
                        if ((targets & AttributeTargets.ReturnValue) != 0)
-                               sb.Append ("'return value' ");
+                               sb.Append ("'return' ");
 
                        if ((targets & AttributeTargets.Struct) != 0)
                                sb.Append ("'struct' ");
@@ -528,270 +635,252 @@ namespace Mono.CSharp {
 
                }
 
-               public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
+               /// <summary>
+               /// Returns AttributeUsage attribute for this type
+               /// </summary>
+               public AttributeUsageAttribute GetAttributeUsage ()
                {
-                       Report.Error (
-                               592, loc, "Attribute '" + a.Name +
-                               "' is not valid on this declaration type. " +
-                               "It is valid on " + GetValidTargets (a) + "declarations only.");
+                       AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute;
+                       if (ua != null)
+                               return ua;
+
+                       Class attr_class = TypeManager.LookupClass (Type);
+
+                       if (attr_class == null) {
+                               object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
+                               ua = (AttributeUsageAttribute)usage_attr [0];
+                               usage_attr_cache.Add (Type, ua);
+                               return ua;
+                       }
+               
+                       return attr_class.AttributeUsage;
                }
 
-                /// <summary>
-                ///   Ensure that Attribute 'a' is being applied to the right language element (target)
-                /// </summary>
-               public static bool CheckAttributeTarget (Attribute a, object element)
+               /// <summary>
+               /// Returns custom name of indexer
+               /// </summary>
+               public string GetIndexerAttributeValue (EmitContext ec)
                {
-                       TypeContainer attr = TypeManager.LookupAttr (a.Type);
-                       AttributeTargets targets = 0;
-
-                       if (attr == null) {
-                               System.Attribute [] attrs = null;
-                               
-                               try {
-                                       attrs = System.Attribute.GetCustomAttributes (a.Type);
+                       if (pos_values == null)
+                               // 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 (ec);
 
-                               } catch {
-                                       Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
-                                                     " (maybe you forgot to set the usage using the" +
-                                                     " AttributeUsage attribute ?).");
-                                       return false;
-                               }
-                                       
-                               foreach (System.Attribute tmp in attrs)
-                                       if (tmp is AttributeUsageAttribute) { 
-                                               targets = ((AttributeUsageAttribute) tmp).ValidOn;
-                                                break;
-                                        }
-                       } else
-                               targets = attr.Targets;
+                       return pos_values [0] as string;
+               }
 
+               /// <summary>
+               /// Returns condition of ConditionalAttribute
+               /// </summary>
+               public string GetConditionalAttributeValue (EmitContext ec)
+               {
+                       if (pos_values == null)
+                               // 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 (ec);
 
-                       if (element is Class) {
-                               if ((targets & AttributeTargets.Class) != 0)
-                                       return true;
-                               else
-                                       return false;
-                               
-                       } else if (element is Struct) {
-                               if ((targets & AttributeTargets.Struct) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Constructor) {
-                               if ((targets & AttributeTargets.Constructor) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Delegate) {
-                               if ((targets & AttributeTargets.Delegate) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Enum) {
-                               if ((targets & AttributeTargets.Enum) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Event) {
-                               if ((targets & AttributeTargets.Event) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Field || element is FieldBuilder) {
-                               if ((targets & AttributeTargets.Field) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Interface) {
-                               if ((targets & AttributeTargets.Interface) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Method || element is Operator ||
-                                   element is Accessor) {
-                               if ((targets & AttributeTargets.Method) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is ParameterBuilder) {
-                               if ((targets & AttributeTargets.Parameter) != 0 ||
-                                    (targets & AttributeTargets.ReturnValue) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is Property || element is Indexer ||
-                                  element is Accessor) {
-                               if ((targets & AttributeTargets.Property) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is AssemblyClass){
-                               if ((targets & AttributeTargets.Assembly) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       } else if (element is ModuleClass){
-                               if ((targets & AttributeTargets.Module) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       }
+                       // Some error occurred
+                       if (pos_values [0] == null)
+                               return null;
 
-                       return false;
+                       return (string)pos_values [0];
                }
 
-               //
-               // This method should be invoked to pull the IndexerName attribute from an
-               // Indexer if it exists.
-               //
-               public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
+               /// <summary>
+               /// Creates the instance of ObsoleteAttribute from this attribute instance
+               /// </summary>
+               public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec)
                {
-                       if (opt_attrs == null)
-                               return null;
-                       if (opt_attrs.AttributeSections == null)
-                               return null;
+                       if (pos_values == null)
+                               // 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 (ec);
 
-                       foreach (AttributeSection asec in opt_attrs.AttributeSections) {
-                               if (asec.Attributes == null)
-                                       continue;
+                       // Some error occurred
+                       if (pos_values == null)
+                               return null;
 
-                               foreach (Attribute a in asec.Attributes){
-                                       if (a.ResolveType (ec) == null)
-                                               return null;
-                                       
-                                       if (a.Type != TypeManager.indexer_name_type)
-                                               continue;
-
-                                       //
-                                       // So we have found an IndexerName, pull the data out.
-                                       //
-                                       if (a.Arguments == null || a.Arguments [0] == null){
-                                               Error_AttributeConstructorMismatch (a.Location);
-                                               return null;
-                                       }
-                                       ArrayList pos_args = (ArrayList) a.Arguments [0];
-                                       if (pos_args.Count == 0){
-                                               Error_AttributeConstructorMismatch (a.Location);
-                                               return null;
-                                       }
-                                       
-                                       Argument arg = (Argument) pos_args [0];
-                                       if (!arg.Resolve (ec, a.Location))
-                                               return null;
-                                       
-                                       Expression e = arg.Expr;
-                                       if (!(e is StringConstant)){
-                                               Error_AttributeConstructorMismatch (a.Location);
-                                               return null;
-                                       }
+                       if (pos_values.Length == 0)
+                               return new ObsoleteAttribute ();
 
-                                       //
-                                       // Remove the attribute from the list
-                                       //
-                                       asec.Attributes.Remove (a);
+                       if (pos_values.Length == 1)
+                               return new ObsoleteAttribute ((string)pos_values [0]);
 
-                                       return (((StringConstant) e).Value);
-                               }
-                       }
-                       return null;
+                       return new ObsoleteAttribute ((string)pos_values [0], (bool)pos_values [1]);
                }
 
-               //
-               // This pulls the condition name out of a Conditional attribute
-               //
-               public string Conditional_GetConditionName ()
+               /// <summary>
+               /// 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.  
+               /// </summary>
+               public bool GetClsCompliantAttributeValue (EmitContext ec)
                {
-                       //
-                       // So we have a Conditional, pull the data out.
-                       //
-                       if (Arguments == null || Arguments [0] == null){
-                               Error_AttributeConstructorMismatch (Location);
-                               return null;
-                       }
-
-                       ArrayList pos_args = (ArrayList) Arguments [0];
-                       if (pos_args.Count != 1){
-                               Error_AttributeConstructorMismatch (Location);
-                               return null;
-                       }
+                       if (pos_values == null)
+                               // 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 (ec);
 
-                       Argument arg = (Argument) pos_args [0]; 
-                       if (!(arg.Expr is StringConstant)){
-                               Error_AttributeConstructorMismatch (Location);
-                               return null;
-                       }
+                       // Some error occurred
+                       if (pos_values [0] == null)
+                               return false;
 
-                       return ((StringConstant) arg.Expr).Value;
+                       return (bool)pos_values [0];
                }
 
-               //
-               // This pulls the obsolete message and error flag out of an Obsolete attribute
-               //
-               public string Obsolete_GetObsoleteMessage (out bool is_error)
+               /// <summary>
+               /// Tests permitted SecurityAction for assembly or other types
+               /// </summary>
+               public bool CheckSecurityActionValidity (bool for_assembly)
                {
-                       is_error = false;
-                       //
-                       // So we have an Obsolete, pull the data out.
-                       //
-                       if (Arguments == null || Arguments [0] == null)
-                               return "";
+                       SecurityAction action  = GetSecurityActionValue ();
 
-                       ArrayList pos_args = (ArrayList) Arguments [0];
-                       if (pos_args.Count == 0)
-                               return "";
-                       else if (pos_args.Count > 2){
-                               Error_AttributeConstructorMismatch (Location);
-                               return null;
-                       }
-
-                       Argument arg = (Argument) pos_args [0]; 
-                       if (!(arg.Expr is StringConstant)){
-                               Error_AttributeConstructorMismatch (Location);
-                               return null;
-                       }
+                       if ((action == SecurityAction.RequestMinimum || action == SecurityAction.RequestOptional || action == SecurityAction.RequestRefuse) && for_assembly)
+                               return true;
 
-                       if (pos_args.Count == 2){
-                               Argument arg2 = (Argument) pos_args [1];
-                               if (!(arg2.Expr is BoolConstant)){
-                                       Error_AttributeConstructorMismatch (Location);
-                                       return null;
+                       if (!for_assembly) {
+                               if (action < SecurityAction.Demand || action > SecurityAction.InheritanceDemand) {
+                                       Error_AttributeEmitError ("SecurityAction is out of range");
+                                       return false;
                                }
-                               is_error = ((BoolConstant) arg2.Expr).Value;
+
+                               if ((action != SecurityAction.RequestMinimum && action != SecurityAction.RequestOptional && action != SecurityAction.RequestRefuse) && !for_assembly)
+                                       return true;
                        }
 
-                       return ((StringConstant) arg.Expr).Value;
+                       Error_AttributeEmitError (String.Concat ("SecurityAction '", action, "' is not valid for this declaration"));
+                       return false;
                }
 
-               static object GetFieldValue (Attribute a, string name)
-                {
-                       int i;
-                       if (a.field_info_arr == null)
-                               return null;
-                       i = 0;
-                       foreach (FieldInfo fi in a.field_info_arr) {
+               System.Security.Permissions.SecurityAction GetSecurityActionValue ()
+               {
+                       return (SecurityAction)pos_values [0];
+               }
+
+               /// <summary>
+               /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
+               /// </summary>
+               /// <returns></returns>
+               public void ExtractSecurityPermissionSet (ListDictionary permissions)
+               {
+                       if (TypeManager.LookupDeclSpace (Type) != null && RootContext.StdLib) {
+                               Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
+                               return;
+                       }
+
+                       SecurityAttribute sa;
+                       // For all assemblies except corlib we can avoid all hacks
+                       if (RootContext.StdLib) {
+                               sa = (SecurityAttribute) Activator.CreateInstance (Type, pos_values);
+
+                               if (prop_info_arr != null) {
+                                       for (int i = 0; i < prop_info_arr.Length; ++i) {
+                                               PropertyInfo pi = prop_info_arr [i];
+                                               pi.SetValue (sa, prop_values_arr [i], null);
+                                       }
+                               }
+                       } else {
+                               Type temp_type = Type.GetType (Type.FullName);
+                               // HACK: All mscorlib attributes have same ctor syntax
+                               sa = (SecurityAttribute) Activator.CreateInstance (temp_type, new object[] { GetSecurityActionValue () } );
+
+                               // All types are from newly created corlib but for invocation with old we need to convert them
+                               if (prop_info_arr != null) {
+                                       for (int i = 0; i < prop_info_arr.Length; ++i) {
+                                               PropertyInfo emited_pi = prop_info_arr [i];
+                                               PropertyInfo pi = temp_type.GetProperty (emited_pi.Name, emited_pi.PropertyType);
+
+                                               object old_instance = pi.PropertyType.IsEnum ?
+                                                       System.Enum.ToObject (pi.PropertyType, prop_values_arr [i]) :
+                                                       prop_values_arr [i];
+
+                                               pi.SetValue (sa, old_instance, null);
+                                       }
+                               }
+                       }
+
+                       IPermission perm = sa.CreatePermission ();
+                       SecurityAction action;
+
+                       // IS is correct because for corlib we are using an instance from old corlib
+                       if (perm is System.Security.CodeAccessPermission) {
+                               action = GetSecurityActionValue ();
+                       } else {
+                               switch (GetSecurityActionValue ()) {
+                                       case SecurityAction.Demand:
+                                               action = (SecurityAction)13;
+                                               break;
+                                       case SecurityAction.LinkDemand:
+                                               action = (SecurityAction)14;
+                                               break;
+                                       case SecurityAction.InheritanceDemand:
+                                               action = (SecurityAction)15;
+                                               break;
+                                       default:
+                                               Error_AttributeEmitError ("Invalid SecurityAction for non-Code Access Security permission");
+                                               return;
+                               }
+                       }
+
+                       PermissionSet ps = (PermissionSet)permissions [action];
+                       if (ps == null) {
+                               ps = new PermissionSet (PermissionState.None);
+                               permissions.Add (action, ps);
+                       }
+                       ps.AddPermission (sa.CreatePermission ());
+               }
+
+               object GetValue (object value)
+               {
+                       if (value is EnumConstant)
+                               return ((EnumConstant) value).GetValue ();
+                       else
+                               return value;                           
+               }
+
+               public object GetPositionalValue (int i)
+               {
+                       return (pos_values == null) ? null : pos_values[i];
+               }
+
+               object GetFieldValue (string name)
+                {
+                       int i;
+                       if (field_info_arr == null)
+                               return null;
+                       i = 0;
+                       foreach (FieldInfo fi in field_info_arr) {
                                if (fi.Name == name)
-                                       return a.field_values_arr [i];
+                                       return GetValue (field_values_arr [i]);
                                i++;
                        }
                        return null;
                }
 
-               static UnmanagedMarshal GetMarshal (Attribute a)
+               public UnmanagedMarshal GetMarshal (Attributable attr)
                {
-                       object o = GetFieldValue (a, "ArraySubType");
+                       object value = GetFieldValue ("SizeParamIndex");
+                       if (value != null && UnmanagedType != UnmanagedType.LPArray) {
+                               Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
+                               return null;
+                       }
+
+                       object o = GetFieldValue ("ArraySubType");
                        UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
                        
-                       switch (a.UnmanagedType) {
+                       switch (UnmanagedType) {
                        case UnmanagedType.CustomMarshaler:
                                MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
                                                                        BindingFlags.Static | BindingFlags.Public);
-                               if (define_custom == null)
+                               if (define_custom == null) {
+                                       Report.RuntimeMissingSupport (Location, "set marshal info");
                                        return null;
+                               }
                                
                                object [] args = new object [4];
-                               args [0] = GetFieldValue (a, "MarshalTypeRef");
-                               args [1] = GetFieldValue (a, "MarshalCookie");
-                               args [2] = GetFieldValue (a, "MarshalType");
+                               args [0] = GetFieldValue ("MarshalTypeRef");
+                               args [1] = GetFieldValue ("MarshalCookie");
+                               args [2] = GetFieldValue ("MarshalType");
                                args [3] = Guid.Empty;
                                return (UnmanagedMarshal) define_custom.Invoke (null, args);
                                
@@ -802,250 +891,105 @@ namespace Mono.CSharp {
                                return UnmanagedMarshal.DefineSafeArray (array_sub_type);
                        
                        case UnmanagedType.ByValArray:
-                               return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));
+                               FieldMember fm = attr as FieldMember;
+                               if (fm == null) {
+                                       Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
+                                       return null;
+                               }
+                               return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
                        
                        case UnmanagedType.ByValTStr:
-                               return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));
+                               return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
                        
                        default:
-                               return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
+                               return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
                        }
                }
 
+               public bool IsInternalCall
+               {
+                       get { return ImplOptions == MethodImplOptions.InternalCall; }
+               }
+
                /// <summary>
-               ///   Applies the attributes specified on target 'kind' to the `builder'.
+               /// Emit attribute for Attributable symbol
                /// </summary>
-               public static void ApplyAttributes (EmitContext ec, object builder, object kind,
-                                                   Attributes opt_attrs)
+               public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr)
                {
-                       Type attr_type = null;
-                       
-                       if (opt_attrs == null)
+                       CustomAttributeBuilder cb = Resolve (ec);
+                       if (cb == null)
                                return;
-                       if (opt_attrs.AttributeSections == null)
-                               return;
-
-                       ArrayList emitted_attrs = new ArrayList ();
-                       ArrayList emitted_targets = new ArrayList ();
-
-                       foreach (AttributeSection asec in opt_attrs.AttributeSections) {
-                               string attr_target = asec.Target;
-                               
-                               if (asec.Attributes == null)
-                                       continue;
-
-                               if (attr_target == "return" && !(builder is ParameterBuilder))
-                                       continue;
-                               
-                               foreach (Attribute a in asec.Attributes) {
-                                       Location loc = a.Location;
-                                       CustomAttributeBuilder cb = a.Resolve (ec);
-                                       attr_type = a.Type;
 
-                                       if (cb == null) 
-                                               continue;
-                                       
-                                       if (!(kind is TypeContainer))
-                                               if (!CheckAttributeTarget (a, kind)) {
-                                                       Error_AttributeNotValidForElement (a, loc);
-                                                       return;
-                                               }
+                       AttributeUsageAttribute usage_attr = GetAttributeUsage ();
+                       if ((usage_attr.ValidOn & Target) == 0) {
+                               Report.Error (592, Location, "Attribute '{0}' is not valid on this declaration type. It is valid on {1} declarations only.", Name, GetValidTargets ());
+                               return;
+                       }
 
-                                       //
-                                       // Perform the check for duplicate attributes
-                                       //
-                                       if (emitted_attrs.Contains (attr_type) &&
-                                           emitted_targets.Contains (attr_target) &&
-                                           !TypeManager.AreMultipleAllowed (attr_type)) {
-                                               Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
-                                               return;
-                                       }
+                       ias.ApplyAttributeBuilder (this, cb);
 
-                                       if (kind is IAttributeSupport) {
-                                               if (attr_type == TypeManager.methodimpl_attr_type && a.ImplOptions == MethodImplOptions.InternalCall) {
-                                                       ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
-                                               } 
-                                               else {
-                                                       IAttributeSupport attributeSupport = kind as IAttributeSupport;
-                                                       attributeSupport.SetCustomAttribute (cb);
-                                               }
-                                       }
-                                       else if (kind is Method || kind is Operator || kind is Accessor) {
-                                               if (attr_type == TypeManager.methodimpl_attr_type) {
-                                                       if (a.ImplOptions == MethodImplOptions.InternalCall)
-                                                               ((MethodBuilder) builder).
-                                                               SetImplementationFlags (
-                                                                       MethodImplAttributes.InternalCall |
-                                                                       MethodImplAttributes.Runtime);
-                                                       else
-                                                               ((MethodBuilder) builder).SetCustomAttribute (cb);
-                                               } else if (attr_type != TypeManager.dllimport_type){
-                                                       ((MethodBuilder) builder).SetCustomAttribute (cb);
-                                               }
-                                       } else if (kind is Constructor) {
-                                               ((ConstructorBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is Field) {
-                                               if (attr_type == TypeManager.marshal_as_attr_type) {
-                                                       UnmanagedMarshal marshal = GetMarshal (a);
-                                                       if (marshal == null) {
-                                                               Report.Warning (-24, loc,
-                                                                       "The Microsoft Runtime cannot set this marshal info. " +
-                                                                       "Please use the Mono runtime instead.");
-                                                       } else {
-                                                               ((FieldBuilder) builder).SetMarshal (marshal);
-                                                       }
-                                               } else { 
-                                                       ((FieldBuilder) builder).SetCustomAttribute (cb);
-                                               }
-                                       } else if (kind is Property || kind is Indexer) {
-
-                                                if (builder is PropertyBuilder) 
-                                                        ((PropertyBuilder) builder).SetCustomAttribute (cb);
-                                                //
-                                                // This is for the case we are setting attributes on
-                                                // the get and set accessors
-                                                //
-                                                else if (builder is MethodBuilder)
-                                                        ((MethodBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is Event) {
-                                               ((MyEventBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is ParameterBuilder) {
-
-                                               if (attr_type == TypeManager.marshal_as_attr_type) {
-                                                       UnmanagedMarshal marshal = GetMarshal (a);
-                                                       if (marshal == null) {
-                                                               Report.Warning (-24, loc,
-                                                                       "The Microsoft Runtime cannot set this marshal info. " +
-                                                                       "Please use the Mono runtime instead.");
-                                                       } else {
-                                                               ((ParameterBuilder) builder).SetMarshal (marshal);
-                                                       }
-                                               } else { 
-
-                                                       try {
-                                                               ((ParameterBuilder) builder).SetCustomAttribute (cb);
-                                                       } catch (System.ArgumentException) {
-                                                               Report.Warning (-24, loc,
-                                                                               "The Microsoft Runtime cannot set attributes \n" +
-                                                                               "on the return type of a method. Please use the \n" +
-                                                                               "Mono runtime instead.");
-                                                       }
+                       if (!usage_attr.AllowMultiple) {
+                               ArrayList emitted_targets = (ArrayList)emitted_attr [Type];
+                               if (emitted_targets == null) {
+                                       emitted_targets = new ArrayList ();
+                                       emitted_attr.Add (Type, emitted_targets);
+                               } else if (emitted_targets.Contains (Target)) {
+                                       Report.Error (579, Location, "Duplicate '" + Name + "' attribute");
+                                       return;
+                               }
+                               emitted_targets.Add (Target);
+                       }
 
-                                               }
-                                       } else if (kind is Enum) {
-                                               ((TypeBuilder) builder).SetCustomAttribute (cb); 
+                       if (!RootContext.VerifyClsCompliance)
+                               return;
 
-                                       } else if (kind is TypeContainer) {
-                                               TypeContainer tc = (TypeContainer) kind;
-                                               
-                                               if (a.UsageAttr) {
-                                                       tc.Targets = a.Targets;
-                                                       tc.AllowMultiple = a.AllowMultiple;
-                                                       tc.Inherited = a.Inherited;
-
-                                                       TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
-                                                                                                   tc.AllowMultiple);
-                                                       
-                                               } else if (attr_type == TypeManager.default_member_type) {
-                                                       if (tc.Indexers != null) {
-                                                               Report.Error (646, loc,
-                                                                     "Cannot specify the DefaultMember attribute on" +
-                                                                     " a type containing an indexer");
-                                                               return;
-                                                       }
-
-                                               } else {
-                                                       if (!CheckAttributeTarget (a, kind)) {
-                                                               Error_AttributeNotValidForElement (a, loc);
-                                                               return;
-                                                       }
-                                               }
+                       // Here we are testing attribute arguments for array usage (error 3016)
+                       if (ias.IsClsCompliaceRequired (ec.DeclSpace)) {
+                               if (Arguments == null)
+                                       return;
 
-                                               try {
-                                                       ((TypeBuilder) builder).SetCustomAttribute (cb);
-                                               } catch (System.ArgumentException) {
-                                                       Report.Warning (
-                                                               -21, loc,
-                                               "The CharSet named property on StructLayout\n"+
-                                               "\tdoes not work correctly on Microsoft.NET\n"+
-                                               "\tYou might want to remove the CharSet declaration\n"+
-                                               "\tor compile using the Mono runtime instead of the\n"+
-                                               "\tMicrosoft .NET runtime");
-                                               }
-                                       } else if (kind is Delegate){
-                                               if (!CheckAttributeTarget (a, kind)) {
-                                                       Error_AttributeNotValidForElement (a, loc);
+                               ArrayList pos_args = (ArrayList) Arguments [0];
+                               if (pos_args != null) {
+                                       foreach (Argument arg in pos_args) { 
+                                               // Type is undefined (was error 246)
+                                               if (arg.Type == null)
                                                        return;
-                                               }
-                                               try {
-                                                       ((TypeBuilder) builder).SetCustomAttribute (cb);
-                                               } catch (System.ArgumentException) {
-                                                       Report.Warning (
-                                                               -21, loc,
-                                               "The CharSet named property on StructLayout\n"+
-                                               "\tdoes not work correctly on Microsoft.NET\n"+
-                                               "\tYou might want to remove the CharSet declaration\n"+
-                                               "\tor compile using the Mono runtime instead of the\n"+
-                                               "\tMicrosoft .NET runtime");
-                                               }
-                                       } else if (kind is Interface) {
-                                               Interface iface = (Interface) kind;
-
-                                               if ((attr_type == TypeManager.default_member_type) &&
-                                                   (iface.Indexers != null)) {
-                                                       Report.Error (
-                                                               646, loc,
-                                                               "Cannot specify the DefaultMember attribute on" +
-                                                               " a type containing an indexer");
-                                                       return;
-                                               }
 
-                                               if (!CheckAttributeTarget (a, kind)) {
-                                                       Error_AttributeNotValidForElement (a, loc);
+                                               if (arg.Type.IsArray) {
+                                                       Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
                                                        return;
                                                }
+                                       }
+                               }
+                       
+                               if (Arguments.Count < 2)
+                                       return;
+                       
+                               ArrayList named_args = (ArrayList) Arguments [1];
+                               foreach (DictionaryEntry de in named_args) {
+                                       Argument arg  = (Argument) de.Value;
 
-                                               ((TypeBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is AssemblyBuilder){
-                                               ((AssemblyBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is ModuleBuilder) {
-                                               ((ModuleBuilder) builder).SetCustomAttribute (cb);
-                                       } else if (kind is FieldBuilder) {
-                                               if (attr_type == TypeManager.marshal_as_attr_type) {
-                                                       UnmanagedMarshal marshal = GetMarshal (a);
-                                                       if (marshal == null) {
-                                                               Report.Warning (-24, loc,
-                                                                       "The Microsoft Runtime cannot set this marshal info. " +
-                                                                       "Please use the Mono runtime instead.");
-                                                       } else {
-                                                               ((ParameterBuilder) builder).SetMarshal (marshal);
-                                                       }
-                                               } else { 
-                                                       ((FieldBuilder) builder).SetCustomAttribute (cb);
-                                               }
-                                       } else
-                                               throw new Exception ("Unknown kind: " + kind);
-
-                                       //
-                                       // Once an attribute type has been emitted once we
-                                       // keep track of the info to prevent multiple occurences
-                                       // for attributes which do not explicitly allow it
-                                       //
-                                       if (!emitted_attrs.Contains (attr_type))
-                                               emitted_attrs.Add (attr_type);
-
-                                       //
-                                       // We keep of this target-wise and so emitted targets
-                                       // are tracked too
-                                       //
-                                       if (!emitted_targets.Contains (attr_target))
-                                               emitted_targets.Add (attr_target);
+                                       // Type is undefined (was error 246)
+                                       if (arg.Type == null)
+                                               return;
+
+                                       if (arg.Type.IsArray) {
+                                               Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
+                                               return;
+                                       }
                                }
-                               
-                               
                        }
                }
 
+               public object GetValue (EmitContext ec, Constant c, Type target)
+               {
+                       if (Convert.ImplicitConversionExists (ec, c, target))
+                               return c.GetValue ();
+
+                       Convert.Error_CannotImplicitConversion (Location, c.Type, target);
+                       return null;
+               }
+               
                public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
                                                          MethodAttributes flags, Type ret_type, Type [] param_types)
                {
@@ -1058,7 +1002,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       Type = CheckAttributeType (ec);
+                       ResolveType (ec);
                        if (Type == null)
                                return null;
                        
@@ -1125,21 +1069,29 @@ namespace Mono.CSharp {
 
                                        if (a.Expr is Constant) {
                                                Constant c = (Constant) a.Expr;
-                                               
-                                               if (member_name == "CallingConvention")
-                                                       cc = (CallingConvention) c.GetValue ();
-                                               else if (member_name == "CharSet")
-                                                       charset = (CharSet) c.GetValue ();
-                                               else if (member_name == "EntryPoint")
-                                                       entry_point = (string) c.GetValue ();
-                                               else if (member_name == "SetLastError")
-                                                       set_last_err = (bool) c.GetValue ();
+
+                                               try {
+                                                       if (member_name == "CallingConvention"){
+                                                               object val = GetValue (ec, c, typeof (CallingConvention));
+                                                               if (val == null)
+                                                                       return null;
+                                                               cc = (CallingConvention) val;
+                                                       } else if (member_name == "CharSet"){
+                                                               charset = (CharSet) c.GetValue ();
+                                                       } else if (member_name == "EntryPoint")
+                                                               entry_point = (string) c.GetValue ();
+                                                       else if (member_name == "SetLastError")
+                                                               set_last_err = (bool) c.GetValue ();
 #if FIXME
-                                               else if (member_name == "ExactSpelling")
-                                                       exact_spelling = (bool) c.GetValue ();
+                                                       else if (member_name == "ExactSpelling")
+                                                               exact_spelling = (bool) c.GetValue ();
 #endif
-                                               else if (member_name == "PreserveSig")
-                                                       preserve_sig = (bool) c.GetValue ();
+                                                       else if (member_name == "PreserveSig")
+                                                               preserve_sig = (bool) c.GetValue ();
+                                               } catch (InvalidCastException){
+                                                       Error_InvalidNamedArgument (member_name);
+                                                       Error_AttributeArgumentNotValid (Location);
+                                               }
                                        } else { 
                                                Error_AttributeArgumentNotValid (Location);
                                                return null;
@@ -1197,48 +1149,449 @@ namespace Mono.CSharp {
                }
        }
        
-       public class AttributeSection {
-               public readonly string    Target;
-               public readonly ArrayList Attributes;
-               
-               public AttributeSection (string target, ArrayList attrs)
+
+       /// <summary>
+       /// For global attributes (assembly, module) we need special handling.
+       /// Attributes can be located in the several files
+       /// </summary>
+       public class GlobalAttribute: Attribute
+       {
+               public readonly NamespaceEntry ns;
+
+               public GlobalAttribute (TypeContainer container, string target, string name, ArrayList args, Location loc):
+                       base (target, name, args, loc)
                {
-                       Target = target;
-                       Attributes = attrs;
+                       ns = container.NamespaceEntry;
+               }
+
+               protected override Type CheckAttributeType (EmitContext ec)
+               {
+                       // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
+                       // each time a new file is parsed.  However, we need to use the NamespaceEntry
+                       // in effect where the attribute was used.  Since code elsewhere cannot assume
+                       // that the NamespaceEntry is right, just overwrite it.
+                       //
+                       // Precondition: RootContext.Tree.Types == null || RootContext.Tree.Types == ns.
+                       //               The second case happens when we are recursively invoked from inside Emit.
+
+                       NamespaceEntry old = null;
+                       if (ec.DeclSpace == RootContext.Tree.Types) {
+                               old = ec.DeclSpace.NamespaceEntry;
+                               ec.DeclSpace.NamespaceEntry = ns;
+                               if (old != null && old != ns)
+                                       throw new InternalErrorException (Location + " non-null NamespaceEntry " + old);
+                       }
+
+                       Type retval = base.CheckAttributeType (ec);
+
+                       if (ec.DeclSpace == RootContext.Tree.Types)
+                               ec.DeclSpace.NamespaceEntry = old;
+
+                       return retval;
+               }
+
+               public override CustomAttributeBuilder Resolve (EmitContext ec)
+               {
+                       if (ec.DeclSpace == RootContext.Tree.Types) {
+                               NamespaceEntry old = ec.DeclSpace.NamespaceEntry;
+                               ec.DeclSpace.NamespaceEntry = ns;
+                               if (old != null)
+                                       throw new InternalErrorException (Location + " non-null NamespaceEntry " + old);
+                       }
+
+                       CustomAttributeBuilder retval = base.Resolve (ec);
+
+                       if (ec.DeclSpace == RootContext.Tree.Types)
+                               ec.DeclSpace.NamespaceEntry = null;
+
+                       return retval;
                }
-               
        }
 
        public class Attributes {
-               public ArrayList AttributeSections;
+               public ArrayList Attrs;
 
-               public Attributes (AttributeSection a)
+               public Attributes (Attribute a)
                {
-                       AttributeSections = new ArrayList ();
-                       AttributeSections.Add (a);
+                       Attrs = new ArrayList ();
+                       Attrs.Add (a);
+               }
 
+               public Attributes (ArrayList attrs)
+               {
+                       Attrs = attrs;
                }
 
-               public void AddAttributeSection (AttributeSection a)
+               public void AddAttributes (ArrayList attrs)
                {
-                       if (a != null && !AttributeSections.Contains (a))
-                               AttributeSections.Add (a);
+                       Attrs.AddRange (attrs);
                }
 
-               public bool Contains (Type t)
+               /// <summary>
+               /// Checks whether attribute target is valid for the current element
+               /// </summary>
+               public bool CheckTargets (Attributable member)
                {
-                       foreach (AttributeSection attr_section in AttributeSections){
-                               foreach (Attribute a in attr_section.Attributes){
-                                       if (a.Type == t)
-                                               return true;
+                       string[] valid_targets = member.ValidAttributeTargets;
+                       foreach (Attribute a in Attrs) {
+                               if (a.ExplicitTarget == null || a.ExplicitTarget == valid_targets [0]) {
+                                       a.Target = member.AttributeTargets;
+                                       continue;
+                               }
+
+                               // TODO: we can skip the first item
+                               if (((IList) valid_targets).Contains (a.ExplicitTarget)) {
+                                       switch (a.ExplicitTarget) {
+                                               case "return": a.Target = AttributeTargets.ReturnValue; continue;
+                                               case "param": a.Target = AttributeTargets.Parameter; continue;
+                                               case "field": a.Target = AttributeTargets.Field; continue;
+                                               case "method": a.Target = AttributeTargets.Method; continue;
+                                               case "property": a.Target = AttributeTargets.Property; continue;
+                                       }
+                                       throw new InternalErrorException ("Unknown explicit target: " + a.ExplicitTarget);
                                }
+
+                               StringBuilder sb = new StringBuilder ();
+                               foreach (string s in valid_targets) {
+                                       sb.Append (s);
+                                       sb.Append (", ");
+                               }
+                               sb.Remove (sb.Length - 2, 2);
+                               Report.Error (657, a.Location, "'{0}' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are '{1}'", a.ExplicitTarget, sb.ToString ());
+                               return false;
                        }
-                        
-                       return false;
+                       return true;
+               }
+
+               public Attribute Search (Type t, EmitContext ec)
+               {
+                       foreach (Attribute a in Attrs) {
+                               if (a.ResolveType (ec) == t)
+                                       return a;
+                       }
+                       return null;
+               }
+
+               /// <summary>
+               /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
+               /// </summary>
+               public Attribute[] SearchMulti (Type t, EmitContext ec)
+               {
+                       ArrayList ar = null;
+
+                       foreach (Attribute a in Attrs) {
+                               if (a.ResolveType (ec) == t) {
+                                       if (ar == null)
+                                               ar = new ArrayList ();
+                                       ar.Add (a);
+                               }
+                       }
+
+                       return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
+               }
+
+               public void Emit (EmitContext ec, Attributable ias)
+               {
+                       if (!CheckTargets (ias))
+                               return;
+
+                       ListDictionary ld = new ListDictionary ();
+
+                       foreach (Attribute a in Attrs)
+                               a.Emit (ec, ias, ld);
+               }
+
+               public bool Contains (Type t, EmitContext ec)
+               {
+                        return Search (t, ec) != null;
                }
        }
 
-       public interface IAttributeSupport {
-               void SetCustomAttribute (CustomAttributeBuilder customBuilder);
+       /// <summary>
+       /// Helper class for attribute verification routine.
+       /// </summary>
+       sealed class AttributeTester
+       {
+               static PtrHashtable analyzed_types = new PtrHashtable ();
+               static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
+               static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
+               static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
+
+               private AttributeTester ()
+               {
+               }
+
+               /// <summary>
+               /// Returns true if parameters of two compared methods are CLS-Compliant.
+               /// It tests differing only in ref or out, or in array rank.
+               /// </summary>
+               public static bool AreOverloadedMethodParamsClsCompliant (Type[] types_a, Type[] types_b) 
+               {
+                       if (types_a == null || types_b == null)
+                               return true;
+
+                       if (types_a.Length != types_b.Length)
+                               return true;
+
+                       for (int i = 0; i < types_b.Length; ++i) {
+                               Type aType = types_a [i];
+                               Type bType = types_b [i];
+
+                               if (aType.IsArray && bType.IsArray && aType.GetArrayRank () != bType.GetArrayRank () && aType.GetElementType () == bType.GetElementType ()) {
+                                       return false;
+                               }
+
+                               Type aBaseType = aType;
+                               bool is_either_ref_or_out = false;
+
+                               if (aType.IsByRef || aType.IsPointer) {
+                                       aBaseType = aType.GetElementType ();
+                                       is_either_ref_or_out = true;
+                               }
+
+                               Type bBaseType = bType;
+                               if (bType.IsByRef || bType.IsPointer) 
+                               {
+                                       bBaseType = bType.GetElementType ();
+                                       is_either_ref_or_out = !is_either_ref_or_out;
+                               }
+
+                               if (aBaseType != bBaseType)
+                                       continue;
+
+                               if (is_either_ref_or_out)
+                                       return false;
+                       }
+                       return true;
+               }
+
+               /// <summary>
+               /// Goes through all parameters and test if they are CLS-Compliant.
+               /// </summary>
+               public static bool AreParametersCompliant (Parameter[] fixedParameters, Location loc)
+               {
+                       if (fixedParameters == null)
+                               return true;
+
+                       foreach (Parameter arg in fixedParameters) {
+                               if (!AttributeTester.IsClsCompliant (arg.ParameterType)) {
+                                       Report.Error (3001, loc, "Argument type '{0}' is not CLS-compliant", arg.GetSignatureForError ());
+                                       return false;
+                               }
+                       }
+                       return true;
+               }
+
+
+               /// <summary>
+               /// This method tests the CLS compliance of external types. It doesn't test type visibility.
+               /// </summary>
+               public static bool IsClsCompliant (Type type) 
+               {
+                       if (type == null)
+                               return true;
+
+                       object type_compliance = analyzed_types[type];
+                       if (type_compliance != null)
+                               return type_compliance == TRUE;
+
+                       if (type.IsPointer) {
+                               analyzed_types.Add (type, null);
+                               return false;
+                       }
+
+                       bool result;
+                       if (type.IsArray || type.IsByRef)       {
+                               result = IsClsCompliant (TypeManager.GetElementType (type));
+                       } else {
+                               result = AnalyzeTypeCompliance (type);
+                       }
+                       analyzed_types.Add (type, result ? TRUE : FALSE);
+                       return result;
+               }                
+
+               static object TRUE = new object ();
+               static object FALSE = new object ();
+
+               public static void VerifyModulesClsCompliance ()
+               {
+                       Module[] modules = TypeManager.Modules;
+                       if (modules == null)
+                               return;
+
+                       // The first module is generated assembly
+                       for (int i = 1; i < modules.Length; ++i) {
+                               Module module = modules [i];
+                               if (!IsClsCompliant (module)) {
+                                       Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute to match the assembly", module.Name);
+                                       return;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Tests container name for CLS-Compliant name (differing only in case)
+               /// </summary>
+               public static void VerifyTopLevelNameClsCompliance ()
+               {
+                       Hashtable locase_table = new Hashtable ();
+
+                       // Convert imported type names to lower case and ignore not cls compliant
+                       foreach (DictionaryEntry de in TypeManager.all_imported_types) {
+                               Type t = (Type)de.Value;
+                               if (!AttributeTester.IsClsCompliant (t))
+                                       continue;
+
+                               locase_table.Add (((string)de.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture), t);
+                       }
+
+                       foreach (DictionaryEntry de in RootContext.Tree.Decls) {
+                               DeclSpace decl = (DeclSpace)de.Value;
+                               if (!decl.IsClsCompliaceRequired (decl))
+                                       continue;
+
+                               string lcase = decl.Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
+                               if (!locase_table.Contains (lcase)) {
+                                       locase_table.Add (lcase, decl);
+                                       continue;
+                               }
+
+                               object conflict = locase_table [lcase];
+                               if (conflict is Type)
+                                       Report.SymbolRelatedToPreviousError ((Type)conflict);
+                               else
+                                       Report.SymbolRelatedToPreviousError ((MemberCore)conflict);
+
+                               Report.Error (3005, decl.Location, "Identifier '{0}' differing only in case is not CLS-compliant", decl.GetSignatureForError ());
+                       }
+               }
+
+               static bool IsClsCompliant (ICustomAttributeProvider attribute_provider) 
+               {
+                       object[] CompliantAttribute = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
+                       if (CompliantAttribute.Length == 0)
+                               return false;
+
+                       return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
+               }
+
+               static bool AnalyzeTypeCompliance (Type type)
+               {
+                       DeclSpace ds = TypeManager.LookupDeclSpace (type);
+                       if (ds != null) {
+                               return ds.IsClsCompliaceRequired (ds.Parent);
+                       }
+
+                       object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
+                       if (CompliantAttribute.Length == 0) 
+                               return IsClsCompliant (type.Assembly);
+
+                       return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
+               }
+
+               /// <summary>
+               /// Returns instance of ObsoleteAttribute when type is obsolete
+               /// </summary>
+               public static ObsoleteAttribute GetObsoleteAttribute (Type type)
+               {
+                       object type_obsolete = analyzed_types_obsolete [type];
+                       if (type_obsolete == FALSE)
+                               return null;
+
+                       if (type_obsolete != null)
+                               return (ObsoleteAttribute)type_obsolete;
+
+                       ObsoleteAttribute result = null;
+                       if (type.IsByRef || type.IsArray || type.IsPointer) {
+                               result = GetObsoleteAttribute (TypeManager.GetElementType (type));
+                       } else {
+                               DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
+
+                               // Type is external, we can get attribute directly
+                               if (type_ds == null) {
+                                       object[] attribute = type.GetCustomAttributes (TypeManager.obsolete_attribute_type, false);
+                                       if (attribute.Length == 1)
+                                               result = (ObsoleteAttribute)attribute [0];
+                               } else {
+                                       result = type_ds.GetObsoleteAttribute (type_ds);
+                               }
+                       }
+
+                       analyzed_types_obsolete.Add (type, result == null ? FALSE : result);
+                       return result;
+               }
+
+               /// <summary>
+               /// Returns instance of ObsoleteAttribute when method is obsolete
+               /// </summary>
+               public static ObsoleteAttribute GetMethodObsoleteAttribute (MethodBase mb)
+               {
+                       IMethodData mc = TypeManager.GetMethod (mb);
+                       if (mc != null) 
+                               return mc.GetObsoleteAttribute ();
+
+                       // compiler generated methods are not registered by AddMethod
+                       if (mb.DeclaringType is TypeBuilder)
+                               return null;
+
+                       return GetMemberObsoleteAttribute (mb);
+               }
+
+               /// <summary>
+               /// Returns instance of ObsoleteAttribute when member is obsolete
+               /// </summary>
+               public static ObsoleteAttribute GetMemberObsoleteAttribute (MemberInfo mi)
+               {
+                       object type_obsolete = analyzed_member_obsolete [mi];
+                       if (type_obsolete == FALSE)
+                               return null;
+
+                       if (type_obsolete != null)
+                               return (ObsoleteAttribute)type_obsolete;
+
+                       ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false) as ObsoleteAttribute;
+                       analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
+                       return oa;
+               }
+
+               /// <summary>
+               /// Common method for Obsolete error/warning reporting.
+               /// </summary>
+               public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc)
+               {
+                       if (oa.IsError) {
+                               Report.Error (619, loc, "'{0}' is obsolete: '{1}'", member, oa.Message);
+                               return;
+                       }
+
+                       if (oa.Message == null) {
+                               Report.Warning (612, loc, "'{0}' is obsolete", member);
+                               return;
+                       }
+                       if (RootContext.WarningLevel >= 2)
+                               Report.Warning (618, loc, "'{0}' is obsolete: '{1}'", member, oa.Message);
+               }
+
+               public static bool IsConditionalMethodExcluded (MethodBase mb)
+               {
+                       object excluded = analyzed_method_excluded [mb];
+                       if (excluded != null)
+                               return excluded == TRUE ? true : false;
+                       
+                       ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[];
+                       if (attrs.Length == 0) {
+                               analyzed_method_excluded.Add (mb, FALSE);
+                               return false;
+                       }
+
+                       foreach (ConditionalAttribute a in attrs) {
+                               if (RootContext.AllDefines.Contains (a.ConditionString)) {
+                                       analyzed_method_excluded.Add (mb, FALSE);
+                                       return false;
+                               }
+                       }
+                       analyzed_method_excluded.Add (mb, TRUE);
+                       return true;
+               }
        }
 }