Update
[mono.git] / mcs / mcs / attribute.cs
index 6abc589eb3c10ccad7cea3e50f6a7613ea035a72..93fee14eff3c29f802baf891ae76322951601f16 100644 (file)
@@ -33,11 +33,9 @@ namespace Mono.CSharp {
                /// </summary>
                Attributes attributes;
 
-               public Attributable(Attributes attrs)
+               public Attributable (Attributes attrs)
                {
                        attributes = attrs;
-                       if (attributes != null)
-                               attributes.CheckTargets (this);
                }
 
                public Attributes OptAttributes 
@@ -47,8 +45,6 @@ namespace Mono.CSharp {
                        }
                        set {
                                attributes = value;
-                               if (attributes != null)
-                                       attributes.CheckTargets (this);
                        }
                }
 
@@ -76,12 +72,17 @@ namespace Mono.CSharp {
                public AttributeTargets Target;
 
                public readonly string    Name;
+               public readonly Expression LeftExpr;
+               public readonly string Identifier;
+
                public readonly ArrayList Arguments;
 
                public readonly Location Location;
 
                public Type Type;
 
+               bool resolve_error;
+
                // Is non-null if type is AttributeUsageAttribute
                AttributeUsageAttribute usage_attribute;
 
@@ -104,9 +105,11 @@ namespace Mono.CSharp {
 
                static PtrHashtable usage_attr_cache = new PtrHashtable ();
                
-               public Attribute (string target, string name, ArrayList args, Location loc)
+               public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc)
                {
-                       Name = name;
+                       LeftExpr = left_expr;
+                       Identifier = identifier;
+                       Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier;
                        Arguments = args;
                        Location = loc;
                        ExplicitTarget = target;
@@ -114,18 +117,24 @@ namespace Mono.CSharp {
 
                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 read-write properties 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)
+               static void Error_AttributeArgumentNotValid (string extra, Location loc)
                {
                        Report.Error (182, loc,
                                      "An attribute argument must be a constant expression, typeof " +
-                                     "expression or array creation expression");
+                                     "expression or array creation expression" + extra);
                }
 
+               static void Error_AttributeArgumentNotValid (Location loc)
+               {
+                       Error_AttributeArgumentNotValid ("", 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.
@@ -146,15 +155,50 @@ namespace Mono.CSharp {
                                       "Could not find a constructor for this argument list.");
                }
 
+               void ResolvePossibleAttributeTypes (EmitContext ec, out Type t1, out Type t2)
+               {
+                       t1 = null;
+                       t2 = null;
+
+                       FullNamedExpression n1 = null;
+                       FullNamedExpression n2 = null;
+                       string IdentifierAttribute = Identifier + "Attribute";
+                       if (LeftExpr == null) {
+                               n1 = new SimpleName (Identifier, Location).ResolveAsTypeStep (ec);
+
+                               // FIXME: Shouldn't do this for quoted attributes: [@A]
+                               n2 = new SimpleName (IdentifierAttribute, Location).ResolveAsTypeStep (ec);
+                       } else {
+                               FullNamedExpression l = LeftExpr.ResolveAsTypeStep (ec);
+                               if (l == null) {
+                                       Report.Error (246, Location, "Couldn't find namespace or type '{0}'", LeftExpr);
+                                       return;
+                               }
+                               n1 = new MemberAccess (l, Identifier, Location).ResolveNamespaceOrType (ec, true);
+
+                               // FIXME: Shouldn't do this for quoted attributes: [X.@A]
+                               n2 = new MemberAccess (l, IdentifierAttribute, Location).ResolveNamespaceOrType (ec, true);
+                       }
+
+                       TypeExpr te1 = n1 == null ? null : n1 as TypeExpr;
+                       TypeExpr te2 = n2 == null ? null : n2 as TypeExpr;                      
+
+                       if (te1 != null)
+                               t1 = te1.ResolveType (ec);
+                       if (te2 != null)
+                               t2 = te2.ResolveType (ec);
+               }
+
                /// <summary>
                 ///   Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
                 /// </summary>
-               protected virtual Type CheckAttributeType (EmitContext ec, bool complain)
+               Type CheckAttributeType (EmitContext ec)
                {
-                       Type t1 = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
+                       Type t1, t2;
+
+                       ResolvePossibleAttributeTypes (ec, out t1, out t2);
 
-                       // FIXME: Shouldn't do this for quoted attributes: [@A]
-                       Type t2 = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
+                       string NameAttribute = Name + "Attribute";
 
                        String err0616 = null;
 
@@ -165,13 +209,13 @@ namespace Mono.CSharp {
                        if (t2 != null && ! t2.IsSubclassOf (TypeManager.attribute_type)) {
                                t2 = null;
                                err0616 = (err0616 != null) 
-                                       ? "Neither '" + Name + "' nor '" + Name + "Attribute' is an attribute class"
+                                       ? "Neither '" + Name + "' nor '" + NameAttribute +"' is an attribute class"
                                        : "'" + Name + "Attribute': is not an attribute class";
                        }
 
                        if (t1 != null && t2 != null) {
                                Report.Error(1614, Location, "'" + Name + "': is ambiguous; " 
-                                            + " use either '@" + Name + "' or '" + Name + "Attribute'");
+                                            + " use either '@" + Name + "' or '" + NameAttribute + "'");
                                return null;
                        }
                        if (t1 != null)
@@ -184,17 +228,18 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (complain)
-                               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, bool complain)
+               public virtual Type ResolveType (EmitContext ec)
                {
                        if (Type == null)
-                               Type = CheckAttributeType (ec, complain);
+                               Type = CheckAttributeType (ec);
                        return Type;
                }
 
@@ -261,12 +306,17 @@ namespace Mono.CSharp {
                        return false;
                }
                
-               public CustomAttributeBuilder Resolve (EmitContext ec)
+               public virtual CustomAttributeBuilder Resolve (EmitContext ec)
                {
+                       if (resolve_error)
+                               return null;
+
+                       resolve_error = true;
+
                        Type oldType = Type;
                        
                        // Sanity check.
-                       Type = CheckAttributeType (ec, true);
+                       Type = CheckAttributeType (ec);
 
                        if (oldType == null && Type == null)
                                return null;
@@ -343,6 +393,10 @@ namespace Mono.CSharp {
 
                                if (DoCompares){
                                        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;
@@ -411,7 +465,13 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
+                               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;
                                }
@@ -482,12 +542,19 @@ namespace Mono.CSharp {
                        // of type object
                        //
 
-                       ParameterData pd = Invocation.GetParameterData (constructor);
+                       ParameterData pd = TypeManager.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];
@@ -497,32 +564,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;
                        }
 
@@ -547,13 +606,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:
@@ -561,10 +613,11 @@ 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 a bug in the .NET runtime. Try the Mono runtime. The exception was: " + e.Message);
+                               Error_AttributeArgumentNotValid (Location);
+                               return null;
                        }
                        
+                       resolve_error = false;
                        return cb;
                }
 
@@ -648,11 +701,10 @@ namespace Mono.CSharp {
                /// </summary>
                public string GetIndexerAttributeValue (EmitContext ec)
                {
-                       if (pos_values == 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);
-                       }
 
                        return pos_values [0] as string;
                }
@@ -660,15 +712,12 @@ namespace Mono.CSharp {
                /// <summary>
                /// Returns condition of ConditionalAttribute
                /// </summary>
-               public string GetConditionalAttributeValue (DeclSpace ds)
+               public string GetConditionalAttributeValue (EmitContext ec)
                {
-                       if (pos_values == null) {
-                               EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
-
+                       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);
-                       }
 
                        // Some error occurred
                        if (pos_values [0] == null)
@@ -680,15 +729,12 @@ namespace Mono.CSharp {
                /// <summary>
                /// Creates the instance of ObsoleteAttribute from this attribute instance
                /// </summary>
-               public ObsoleteAttribute GetObsoleteAttribute (DeclSpace ds)
+               public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec)
                {
-                       if (pos_values == null) {
-                               EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
-
+                       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);
-                       }
 
                        // Some error occurred
                        if (pos_values == null)
@@ -708,15 +754,12 @@ namespace Mono.CSharp {
                /// before ApplyAttribute. We need to resolve the arguments.
                /// This situation occurs when class deps is differs from Emit order.  
                /// </summary>
-               public bool GetClsCompliantAttributeValue (DeclSpace ds)
+               public bool GetClsCompliantAttributeValue (EmitContext ec)
                {
-                       if (pos_values == null) {
-                               EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
-
+                       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);
-                       }
 
                        // Some error occurred
                        if (pos_values [0] == null)
@@ -796,14 +839,19 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       IPermission perm = sa.CreatePermission ();
-                       SecurityAction action;
+                       IPermission perm;
+                       try {
+                               perm = sa.CreatePermission ();
+                       }
+                       catch (Exception e) {
+                               Error_AttributeEmitError (String.Format ("{0} was thrown during attribute processing: {1}", e.GetType (), e.Message));
+                               return;
+                       }
+                       SecurityAction action = GetSecurityActionValue ();
 
                        // 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 ()) {
+                       if (!(perm is System.Security.CodeAccessPermission)) {
+                               switch (action) {
                                        case SecurityAction.Demand:
                                                action = (SecurityAction)13;
                                                break;
@@ -813,18 +861,22 @@ namespace Mono.CSharp {
                                        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);
+                               if (sa is PermissionSetAttribute)
+                                       ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
+                               else
+                                       ps = new PermissionSet (PermissionState.None);
+
                                permissions.Add (action, ps);
+                       } else if (!ps.IsUnrestricted () && sa.Unrestricted) {
+                               ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
+                               permissions [action] = ps;
                        }
-                       ps.AddPermission (sa.CreatePermission ());
+                       ps.AddPermission (perm);
                }
 
                object GetValue (object value)
@@ -999,7 +1051,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       ResolveType (ec, true);
+                       ResolveType (ec);
                        if (Type == null)
                                return null;
                        
@@ -1023,7 +1075,11 @@ namespace Mono.CSharp {
                                Error_AttributeArgumentNotValid (Location);
                                return null;
                        }
-
+                       if (dll_name == null || dll_name == ""){
+                               Error_AttributeArgumentNotValid (": DllImport requires a non-empty string", Location);
+                               return null;
+                       }
+                       
                        // Now we process the named arguments
                        CallingConvention cc = CallingConvention.Winapi;
                        CharSet charset = CharSet.Ansi;
@@ -1155,18 +1211,47 @@ namespace Mono.CSharp {
        {
                public readonly NamespaceEntry ns;
 
-               public GlobalAttribute (TypeContainer container, string target, string name, ArrayList args, Location loc):
-                       base (target, name, args, loc)
+               public GlobalAttribute (TypeContainer container, string target, 
+                                       Expression left_expr, string identifier, ArrayList args, Location loc):
+                       base (target, left_expr, identifier, args, loc)
                {
                        ns = container.NamespaceEntry;
                }
 
-               protected override Type CheckAttributeType (EmitContext ec, bool complain)
+               void Enter ()
+               {
+                       // 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
+
+                       if (RootContext.Tree.Types.NamespaceEntry != null)
+                               throw new InternalErrorException (Location + " non-null NamespaceEntry");
+
+                       RootContext.Tree.Types.NamespaceEntry = ns;
+               }
+
+               void Leave ()
+               {
+                       RootContext.Tree.Types.NamespaceEntry = null;
+               }
+
+               public override Type ResolveType (EmitContext ec)
                {
-                       NamespaceEntry old = ec.DeclSpace.NamespaceEntry;
-                       if (old == null || old.NS == null || old.NS == Namespace.Root) 
-                               ec.DeclSpace.NamespaceEntry = ns;
-                       return base.CheckAttributeType (ec, complain);
+                       Enter ();
+                       Type retval = base.ResolveType (ec);
+                       Leave ();
+                       return retval;
+               }
+
+               public override CustomAttributeBuilder Resolve (EmitContext ec)
+               {
+                       Enter ();
+                       CustomAttributeBuilder retval = base.Resolve (ec);
+                       Leave ();
+                       return retval;
                }
        }
 
@@ -1192,7 +1277,7 @@ namespace Mono.CSharp {
                /// <summary>
                /// Checks whether attribute target is valid for the current element
                /// </summary>
-               public void CheckTargets (Attributable member)
+               public bool CheckTargets (Attributable member)
                {
                        string[] valid_targets = member.ValidAttributeTargets;
                        foreach (Attribute a in Attrs) {
@@ -1219,24 +1304,21 @@ namespace Mono.CSharp {
                                        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.Target, sb.ToString ());
+                               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 true;
                }
 
-               private Attribute Search (Type t, EmitContext ec, bool complain)
+               public Attribute Search (Type t, EmitContext ec)
                {
                        foreach (Attribute a in Attrs) {
-                               if (a.ResolveType (ec, complain) == t)
+                               if (a.ResolveType (ec) == t)
                                        return a;
                        }
                        return null;
                }
 
-               public Attribute Search (Type t, EmitContext ec)
-               {
-                       return Search (t, ec, true);
-               }
-
                /// <summary>
                /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
                /// </summary>
@@ -1245,7 +1327,7 @@ namespace Mono.CSharp {
                        ArrayList ar = null;
 
                        foreach (Attribute a in Attrs) {
-                               if (a.ResolveType (ec, false) == t) {
+                               if (a.ResolveType (ec) == t) {
                                        if (ar == null)
                                                ar = new ArrayList ();
                                        ar.Add (a);
@@ -1257,6 +1339,9 @@ namespace Mono.CSharp {
 
                public void Emit (EmitContext ec, Attributable ias)
                {
+                       if (!CheckTargets (ias))
+                               return;
+
                        ListDictionary ld = new ListDictionary ();
 
                        foreach (Attribute a in Attrs)
@@ -1267,26 +1352,6 @@ namespace Mono.CSharp {
                {
                         return Search (t, ec) != null;
                }
-
-               public Attribute GetClsCompliantAttribute (EmitContext ec)
-               {
-                       return Search (TypeManager.cls_compliant_attribute_type, ec, false);
-               }
-
-               /// <summary>
-               /// Pulls the IndexerName attribute from an Indexer if it exists.
-               /// </summary>
-               public Attribute GetIndexerNameAttribute (EmitContext ec)
-               {
-                       Attribute a = Search (TypeManager.indexer_name_type, ec, false);
-                       if (a == null)
-                               return null;
-
-                       // Remove the attribute from the list because it is not emitted
-                       Attrs.Remove (a);
-                       return a;
-               }
-
        }
 
        /// <summary>
@@ -1516,6 +1581,10 @@ namespace Mono.CSharp {
                        if (mb.DeclaringType is TypeBuilder)
                                return null;
 
+                       PropertyInfo pi = PropertyExpr.AccessorTable [mb] as PropertyInfo;
+                       if (pi != null)
+                               return GetMemberObsoleteAttribute (pi);
+
                        return GetMemberObsoleteAttribute (mb);
                }