2005-11-07 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / gmcs / parameter.cs
old mode 100755 (executable)
new mode 100644 (file)
index 3dce356..e833db6
@@ -13,6 +13,7 @@ using System;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.Collections;
+using System.Text;
 
 namespace Mono.CSharp {
 
@@ -22,50 +23,59 @@ namespace Mono.CSharp {
        public abstract class ParameterBase : Attributable {
 
                protected ParameterBuilder builder;
+               public readonly Location Location;
 
-               public ParameterBase (Attributes attrs)
+               public ParameterBase (Attributes attrs, Location loc)
                        : base (attrs)
                {
+                       Location = loc;
                }
 
                public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
                {
                        if (a.Type == TypeManager.marshal_as_attr_type) {
-                               UnmanagedMarshal marshal = a.GetMarshal ();
+                               UnmanagedMarshal marshal = a.GetMarshal (this);
                                if (marshal != null) {
                                        builder.SetMarshal (marshal);
+                               }
                                        return;
                        }
-                               Report.Warning_T (-24, a.Location);
+
+                       if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
+                               a.Error_InvalidSecurityParent ();
                                return;
                        }
 
                        builder.SetCustomAttribute (cb);
                }
 
-               public override bool IsClsCompliaceRequired(DeclSpace ds)
+               public override bool IsClsComplianceRequired(DeclSpace ds)
                {
                        return false;
-                               }
+               }
        }
 
        /// <summary>
        /// Class for applying custom attributes on the return type
        /// </summary>
-       public class ReturnParameter: ParameterBase {
+       public class ReturnParameter : ParameterBase {
                public ReturnParameter (MethodBuilder mb, Location location):
-                       base (null)
+                       base (null, location)
                {
                        try {
                                builder = mb.DefineParameter (0, ParameterAttributes.None, "");                 
                        }
                        catch (ArgumentOutOfRangeException) {
-                               Report.Warning_T (-28, location);
+                               Report.Warning (-24, location, "The Microsoft .NET Runtime 1.x does not permit setting custom attributes on the return type");
                        }
                }
 
                public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
                {
+                       if (a.Type == TypeManager.cls_compliant_attribute_type) {
+                               Report.Warning (3023, 1, a.Location, "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
+                       }
+
                        // This occurs after Warning -28
                        if (builder == null)
                                return;
@@ -82,7 +92,7 @@ namespace Mono.CSharp {
                /// <summary>
                /// Is never called
                /// </summary>
-               protected override string[] ValidAttributeTargets {
+               public override string[] ValidAttributeTargets {
                        get {
                                return null;
                        }
@@ -93,9 +103,9 @@ namespace Mono.CSharp {
        /// Class for applying custom attributes on the implicit parameter type
        /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
        /// </summary>
-       public class ImplicitParameter: ParameterBase {
-               public ImplicitParameter (MethodBuilder mb):
-                       base (null)
+       public class ImplicitParameter : ParameterBase {
+               public ImplicitParameter (MethodBuilder mb, Location loc):
+                       base (null, loc)
                {
                        builder = mb.DefineParameter (1, ParameterAttributes.None, "");                 
                }
@@ -109,7 +119,7 @@ namespace Mono.CSharp {
                /// <summary>
                /// Is never called
                /// </summary>
-               protected override string[] ValidAttributeTargets {
+               public override string[] ValidAttributeTargets {
                        get {
                                return null;
                        }
@@ -120,8 +130,6 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Represents a single method parameter
        /// </summary>
-
-       //TODO: Add location member to this or base class for better error location and all methods simplification.
        public class Parameter : ParameterBase {
                [Flags]
                public enum Modifier : byte {
@@ -136,26 +144,56 @@ namespace Mono.CSharp {
 
                static string[] attribute_targets = new string [] { "param" };
 
-               public readonly Expression TypeName;
+               public Expression TypeName;
                public readonly Modifier ModFlags;
                public readonly string Name;
                GenericConstraints constraints;
                Type parameter_type;
+
+               EmitContext ec;  // because ApplyAtrribute doesn't have ec
                
-               public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
-                       : base (attrs)
+               public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Location loc)
+                       : base (attrs, loc)
                {
                        Name = name;
                        ModFlags = mod;
                        TypeName = type;
                }
 
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+               {
+                       if (a.Type == TypeManager.in_attribute_type && Attributes == ParameterAttributes.Out) {
+                               Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
+                               return;
+                       }
+
+                       if (a.Type == TypeManager.param_array_type) {
+                               Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
+                               return;
+                       }
+
+                       if (a.Type == TypeManager.out_attribute_type && (ModFlags & Modifier.REF) != 0 &&
+                           !OptAttributes.Contains (TypeManager.in_attribute_type, ec)) {
+                               Report.Error (662, a.Location,
+                                       "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
+                               return;
+                       }
+
+                       if (a.Type == TypeManager.cls_compliant_attribute_type) {
+                               Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
+                       }
+
+                       base.ApplyAttributeBuilder (a, cb);
+               }
+
                // <summary>
                //   Resolve is used in method definitions
                // </summary>
-               public bool Resolve (DeclSpace ds, Location l)
+               public bool Resolve (EmitContext ec)
                {
-                       TypeExpr texpr = ds.ResolveTypeExpr (TypeName, false, l);
+                       TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec);
+                       this.ec = ec;
+
                        if (texpr == null)
                                return false;
 
@@ -163,18 +201,23 @@ namespace Mono.CSharp {
                        if (tparam != null)
                                constraints = tparam.TypeParameter.Constraints;
 
-                       parameter_type = ds.ResolveType (texpr, l);
+                       parameter_type = texpr.Type;
+
+                       if (parameter_type.IsAbstract && parameter_type.IsSealed) {
+                               Report.Error (721, Location, "`{0}': static types cannot be used as parameters", GetSignatureForError ());
+                               return false;
+                       }
 
                        if (parameter_type == TypeManager.void_type){
-                               Report.Error (1536, l, "`void' parameter is not permitted");
+                               Report.Error (1536, Location, "Invalid parameter type 'void'");
                                return false;
                        }
 
                        if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
                                if (parameter_type == TypeManager.typed_reference_type ||
                                    parameter_type == TypeManager.arg_iterator_type){
-                                       Report.Error (1601, l,
-                                                     "out or ref parameter can not be of type TypedReference or ArgIterator");
+                                       Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
+                                               GetSignatureForError ());
                                        return false;
                                }
                        }
@@ -219,6 +262,23 @@ namespace Mono.CSharp {
                                return ParameterAttributes.None;
                        }
                }
+
+               public static ParameterAttributes GetParameterAttributes (Modifier mod)
+               {
+                       int flags = ((int) mod) & ~((int) Parameter.Modifier.ISBYREF);
+                       switch ((Modifier) flags) {
+                       case Modifier.NONE:
+                               return ParameterAttributes.None;
+                       case Modifier.REF:
+                               return ParameterAttributes.None;
+                       case Modifier.OUT:
+                               return ParameterAttributes.Out;
+                       case Modifier.PARAMS:
+                               return 0;
+                       }
+                               
+                       return ParameterAttributes.None;
+               }
                
                public override AttributeTargets AttributeTargets {
                        get {
@@ -230,10 +290,10 @@ namespace Mono.CSharp {
                ///   Returns the signature for this parameter evaluating it on the
                ///   @tc context
                /// </summary>
-               public string GetSignature (DeclSpace ds, Location loc)
+               public string GetSignature (EmitContext ec)
                {
                        if (parameter_type == null){
-                               if (!Resolve (ds, loc))
+                               if (!Resolve (ec))
                                        return null;
                        }
 
@@ -242,19 +302,38 @@ namespace Mono.CSharp {
 
                public string GetSignatureForError ()
                {
-                       string typeName = TypeManager.CSharpName (parameter_type);
-                       switch (ModFlags & ~Modifier.ISBYREF) {
+                       string type_name;
+                       if (parameter_type != null)
+                               type_name = TypeManager.CSharpName (parameter_type);
+                       else if (TypeName.Type != null)
+                               type_name = TypeManager.CSharpName (TypeName.Type);
+                       else
+                               type_name = TypeName.ToString ();
+
+                       string mod = GetModifierSignature (ModFlags);
+                       if (mod.Length > 0)
+                               return String.Concat (mod, " ", type_name);
+
+                       return type_name;
+               }
+
+               public static string GetModifierSignature (Modifier mod)
+               {
+                       switch (mod & unchecked (~Modifier.ISBYREF)) {
                                case Modifier.OUT:
-                                       return "out " + typeName;
+                                       return "out";
                                case Modifier.PARAMS:
-                                       return "params " + typeName;
+                                       return "params";
                                case Modifier.REF:
-                                       return "ref " + typeName;
+                                       return "ref";
+                               case Modifier.ARGLIST:
+                                       return "__arglist";
+                               default:
+                                       return "";
                        }
-                       return typeName;
                }
 
-               public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
+               public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index)
                {
                        ParameterAttributes par_attr = Attributes;
                                        
@@ -265,15 +344,10 @@ namespace Mono.CSharp {
                                        
                        if (OptAttributes != null) {
                                OptAttributes.Emit (ec, this);
-       
-                               if (par_attr == ParameterAttributes.Out){
-                                       if (OptAttributes.Contains (TypeManager.in_attribute_type, ec))
-                                               Report.Error (36, loc,  "Can not use [In] attribute on out parameter");
-                               }
                        }
                }
 
-               protected override string[] ValidAttributeTargets {
+               public override string[] ValidAttributeTargets {
                        get {
                                return attribute_targets;
                        }
@@ -289,22 +363,19 @@ namespace Mono.CSharp {
                public readonly bool HasArglist;
                string signature;
                Type [] types;
-               Location loc;
                
                static Parameters empty_parameters;
                
-               public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
+               public Parameters (Parameter [] fixed_parameters, Parameter array_parameter)
                {
                        FixedParameters = fixed_parameters;
                        ArrayParameter  = array_parameter;
-                       loc = l;
                }
 
-               public Parameters (Parameter [] fixed_parameters, bool has_arglist, Location l)
+               public Parameters (Parameter [] fixed_parameters, bool has_arglist)
                {
                        FixedParameters = fixed_parameters;
                        HasArglist = has_arglist;
-                       loc = l;
                }
 
                /// <summary>
@@ -314,7 +385,7 @@ namespace Mono.CSharp {
                public static Parameters EmptyReadOnlyParameters {
                        get {
                                if (empty_parameters == null)
-                                       empty_parameters = new Parameters (null, null, Location.Null);
+                                       empty_parameters = new Parameters (null, null);
                        
                                return empty_parameters;
                        }
@@ -325,15 +396,15 @@ namespace Mono.CSharp {
                                return (FixedParameters == null) && (ArrayParameter == null);
                        }
                }
-               
-               public void ComputeSignature (DeclSpace ds)
+
+               public void ComputeSignature (EmitContext ec)
                {
                        signature = "";
                        if (FixedParameters != null){
                                for (int i = 0; i < FixedParameters.Length; i++){
                                        Parameter par = FixedParameters [i];
                                        
-                                       signature += par.GetSignature (ds, loc);
+                                       signature += par.GetSignature (ec);
                                }
                        }
                        //
@@ -342,7 +413,7 @@ namespace Mono.CSharp {
                        //
                }
 
-               void Error_DuplicateParameterName (string name)
+               void Error_DuplicateParameterName (string name, Location loc)
                {
                        Report.Error (
                                100, loc, "The parameter name `" + name + "' is a duplicate");
@@ -358,18 +429,20 @@ namespace Mono.CSharp {
                        
                        count = FixedParameters.Length;
                        string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
+
                        for (i = 0; i < count; i++){
                                string base_name = FixedParameters [i].Name;
-                               
                                for (j = i + 1; j < count; j++){
                                        if (base_name != FixedParameters [j].Name)
                                                continue;
-                                       Error_DuplicateParameterName (base_name);
+                                       Error_DuplicateParameterName (base_name,
+                                               FixedParameters [i].Location);
                                        return false;
                                }
 
                                if (base_name == array_par_name){
-                                       Error_DuplicateParameterName (base_name);
+                                       Error_DuplicateParameterName (base_name,
+                                               FixedParameters [i].Location);
                                        return false;
                                }
                        }
@@ -378,13 +451,13 @@ namespace Mono.CSharp {
                
                /// <summary>
                ///    Returns the signature of the Parameters evaluated in
-               ///    the @tc environment
+               ///    the @ec EmitContext
                /// </summary>
-               public string GetSignature (DeclSpace ds)
+               public string GetSignature (EmitContext ec)
                {
                        if (signature == null){
                                VerifyArgs ();
-                               ComputeSignature (ds);
+                               ComputeSignature (ec);
                        }
                        
                        return signature;
@@ -418,7 +491,14 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               bool ComputeParameterTypes (DeclSpace ds)
+               public Parameter GetParameterByName (string name)
+               {
+                       int idx;
+
+                       return GetParameterByName (name, out idx);
+               }
+               
+               bool ComputeParameterTypes (EmitContext ec)
                {
                        int extra = (ArrayParameter != null) ? 1 : 0;
                        int i = 0;
@@ -441,7 +521,7 @@ namespace Mono.CSharp {
                                foreach (Parameter p in FixedParameters){
                                        Type t = null;
                                        
-                                       if (p.Resolve (ds, loc))
+                                       if (p.Resolve (ec))
                                                t = p.ExternalType ();
                                        else
                                                failed = true;
@@ -452,7 +532,7 @@ namespace Mono.CSharp {
                        }
                        
                        if (extra > 0){
-                               if (ArrayParameter.Resolve (ds, loc))
+                               if (ArrayParameter.Resolve (ec))
                                        types [i] = ArrayParameter.ExternalType ();
                                else 
                                        failed = true;
@@ -465,68 +545,13 @@ namespace Mono.CSharp {
 
                        return true;
                }
-
-               //
-               // This variant is used by Delegates, because they need to
-               // resolve/define names, instead of the plain LookupType
-               //
-               public bool ComputeAndDefineParameterTypes (DeclSpace ds)
-               {
-                       int extra = (ArrayParameter != null) ? 1 : 0;
-                       int i = 0;
-                       int pc;
-
-                       if (FixedParameters == null)
-                               pc = extra;
-                       else
-                               pc = extra + FixedParameters.Length;
-                       
-                       types = new Type [pc];
-                       
-                       if (!VerifyArgs ()){
-                               FixedParameters = null;
-                               return false;
-                       }
-
-                       bool ok_flag = true;
-                       
-                       if (FixedParameters != null){
-                               foreach (Parameter p in FixedParameters){
-                                       Type t = null;
-                                       
-                                       if (p.Resolve (ds, loc))
-                                               t = p.ExternalType ();
-                                       else
-                                               ok_flag = false;
-                                       
-                                       types [i] = t;
-                                       i++;
-                               }
-                       }
-                       
-                       if (extra > 0){
-                               if (ArrayParameter.Resolve (ds, loc))
-                                       types [i] = ArrayParameter.ExternalType ();
-                               else
-                                       ok_flag = false;
-                       }
-
-                       //
-                       // invalidate the cached types
-                       //
-                       if (!ok_flag){
-                               types = null;
-                       }
-                       
-                       return ok_flag;
-               }
                
                /// <summary>
                ///   Returns the argument types as an array
                /// </summary>
                static Type [] no_types = new Type [0];
                
-               public Type [] GetParameterInfo (DeclSpace ds)
+               public Type [] GetParameterInfo (EmitContext ec)
                {
                        if (types != null)
                                return types;
@@ -534,7 +559,7 @@ namespace Mono.CSharp {
                        if (FixedParameters == null && ArrayParameter == null)
                                return no_types;
 
-                       if (ComputeParameterTypes (ds) == false){
+                       if (ComputeParameterTypes (ec) == false){
                                types = null;
                                return null;
                        }
@@ -549,7 +574,7 @@ namespace Mono.CSharp {
                ///   Note that the returned type will not contain any dereference in this
                ///   case (ie, you get "int" for a ref int instead of "int&"
                /// </summary>
-               public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
+               public Type GetParameterInfo (EmitContext ec, int idx, out Parameter.Modifier mod)
                {
                        mod = Parameter.Modifier.NONE;
                        
@@ -562,7 +587,7 @@ namespace Mono.CSharp {
                                return null;
                        
                        if (types == null)
-                               if (ComputeParameterTypes (ds) == false)
+                               if (ComputeParameterTypes (ec) == false)
                                        return null;
 
                        //
@@ -596,9 +621,8 @@ namespace Mono.CSharp {
                // The method's attributes are passed in because we need to extract
                // the "return:" attribute from there to apply on the return type
                //
-               public void LabelParameters (EmitContext ec,
-                       MethodBase builder,
-                       Location loc) {
+               public void LabelParameters (EmitContext ec, MethodBase builder)
+               {
                        //
                        // Define each type attribute (in/out/ref) and
                        // the argument names.
@@ -610,7 +634,7 @@ namespace Mono.CSharp {
 
                        if (FixedParameters != null) {
                                for (i = 0; i < FixedParameters.Length; i++) {
-                                       FixedParameters [i].DefineParameter (ec, mb, cb, i + 1, loc);
+                                       FixedParameters [i].DefineParameter (ec, mb, cb, i + 1);
                                }
                        }
 
@@ -633,5 +657,30 @@ namespace Mono.CSharp {
                                pb.SetCustomAttribute (a);
                        }
                }
+
+               public string GetSignatureForError ()
+               {
+                       StringBuilder sb = new StringBuilder ("(");
+                       if (FixedParameters != null) {
+                               for (int i = 0; i < FixedParameters.Length; ++i) {
+                                       sb.Append (FixedParameters[i].GetSignatureForError ());
+                                       if (i < FixedParameters.Length - 1)
+                                               sb.Append (", ");
+                               }
+                       }
+                       if (ArrayParameter != null) {
+                               if (sb.Length > 0)
+                                       sb.Append (", ");
+                               sb.Append (ArrayParameter.GetSignatureForError ());
+                       }
+                       if (HasArglist) {
+                               if (sb.Length > 0)
+                                       sb.Append (", ");
+                               sb.Append ("__arglist");
+                       }
+                       sb.Append (')');
+                       return sb.ToString ();
+
+               }
        }
 }