2 // parameter.cs: Parameter definition.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Collections;
19 namespace Mono.CSharp {
22 /// Abstract Base class for parameters of a method.
24 public abstract class ParameterBase : Attributable {
26 protected ParameterBuilder builder;
27 public readonly Location Location;
29 protected ParameterBase (Attributes attrs, Location loc)
35 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
37 if (a.Type == TypeManager.marshal_as_attr_type) {
38 UnmanagedMarshal marshal = a.GetMarshal (this);
39 if (marshal != null) {
40 builder.SetMarshal (marshal);
45 if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
46 a.Error_InvalidSecurityParent ();
50 builder.SetCustomAttribute (cb);
53 public override bool IsClsComplianceRequired(DeclSpace ds)
60 /// Class for applying custom attributes on the return type
62 public class ReturnParameter : ParameterBase {
63 public ReturnParameter (MethodBuilder mb, Location location):
67 builder = mb.DefineParameter (0, ParameterAttributes.None, "");
69 catch (ArgumentOutOfRangeException) {
70 Report.RuntimeMissingSupport (Location, "custom attributes on the return type");
74 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
76 if (a.Type == TypeManager.cls_compliant_attribute_type) {
77 Report.Warning (3023, 1, a.Location, "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
80 // This occurs after Warning -28
84 base.ApplyAttributeBuilder (a, cb);
87 public override AttributeTargets AttributeTargets {
89 return AttributeTargets.ReturnValue;
96 public override string[] ValidAttributeTargets {
104 /// Class for applying custom attributes on the implicit parameter type
105 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
108 // TODO: should use more code from Parameter.ApplyAttributeBuilder
109 public class ImplicitParameter : ParameterBase {
110 public ImplicitParameter (MethodBuilder mb, Location loc):
113 builder = mb.DefineParameter (1, ParameterAttributes.None, "");
116 public override AttributeTargets AttributeTargets {
118 return AttributeTargets.Parameter;
125 public override string[] ValidAttributeTargets {
132 public class ParamsParameter : Parameter {
133 public ParamsParameter (Expression type, string name, Attributes attrs, Location loc):
134 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
138 public override bool Resolve (EmitContext ec)
140 if (!base.Resolve (ec))
143 if (!parameter_type.IsArray || parameter_type.GetArrayRank () != 1) {
144 Report.Error (225, Location, "The params parameter must be a single dimensional array");
150 public override void ApplyAttributes (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index)
152 base.ApplyAttributes (ec, mb, cb, index);
154 CustomAttributeBuilder a = new CustomAttributeBuilder (
155 TypeManager.cons_param_array_attribute, new object [0]);
157 builder.SetCustomAttribute (a);
161 public class ArglistParameter : Parameter {
162 // Doesn't have proper type because it's never choosed for better conversion
163 public ArglistParameter () :
164 base (typeof (ArglistParameter), "", Parameter.Modifier.ARGLIST, null, Location.Null)
168 public override bool Resolve (EmitContext ec)
173 public override string GetSignatureForError ()
180 /// Represents a single method parameter
182 public class Parameter : ParameterBase {
184 public enum Modifier : byte {
186 REF = REFMASK | ISBYREF,
187 OUT = OUTMASK | ISBYREF,
189 // This is a flag which says that it's either REF or OUT.
196 static string[] attribute_targets = new string [] { "param" };
198 public Expression TypeName;
199 public readonly Modifier ModFlags;
200 public readonly string Name;
201 GenericConstraints constraints;
202 protected Type parameter_type;
204 EmitContext ec; // because ApplyAtrribute doesn't have ec
206 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Location loc)
214 public Parameter (Type type, string name, Modifier mod, Attributes attrs, Location loc)
219 parameter_type = type;
222 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
224 if (a.Type == TypeManager.in_attribute_type && ModFlags == Modifier.OUT) {
225 Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
229 if (a.Type == TypeManager.param_array_type) {
230 Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
234 if (a.Type == TypeManager.out_attribute_type && (ModFlags & Modifier.REF) == Modifier.REF &&
235 !OptAttributes.Contains (TypeManager.in_attribute_type, ec)) {
236 Report.Error (662, a.Location,
237 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
241 if (a.Type == TypeManager.cls_compliant_attribute_type) {
242 Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
245 base.ApplyAttributeBuilder (a, cb);
249 // Resolve is used in method definitions
251 public virtual bool Resolve (EmitContext ec)
253 if (parameter_type != null)
258 TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec);
263 TypeParameterExpr tparam = texpr as TypeParameterExpr;
265 constraints = tparam.TypeParameter.Constraints;
267 parameter_type = texpr.ResolveType (ec);
269 if (parameter_type.IsAbstract && parameter_type.IsSealed) {
270 Report.Error (721, Location, "`{0}': static types cannot be used as parameters", GetSignatureForError ());
274 if (parameter_type == TypeManager.void_type){
275 Report.Error (1536, Location, "Invalid parameter type 'void'");
279 if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
280 if (parameter_type == TypeManager.typed_reference_type ||
281 parameter_type == TypeManager.arg_iterator_type){
282 Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
283 GetSignatureForError ());
291 public Type ExternalType ()
293 if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
294 return TypeManager.GetReferenceType (parameter_type);
296 return parameter_type;
299 public Type ParameterType {
301 return parameter_type;
305 public GenericConstraints GenericConstraints {
311 public ParameterAttributes Attributes {
315 return ParameterAttributes.None;
317 return ParameterAttributes.None;
319 return ParameterAttributes.Out;
320 case Modifier.PARAMS:
324 return ParameterAttributes.None;
328 public static ParameterAttributes GetParameterAttributes (Modifier mod)
330 int flags = ((int) mod) & ~((int) Parameter.Modifier.ISBYREF);
331 switch ((Modifier) flags) {
333 return ParameterAttributes.None;
335 return ParameterAttributes.None;
337 return ParameterAttributes.Out;
338 case Modifier.PARAMS:
342 return ParameterAttributes.None;
345 public override AttributeTargets AttributeTargets {
347 return AttributeTargets.Parameter;
351 public virtual string GetSignatureForError ()
354 if (parameter_type != null)
355 type_name = TypeManager.CSharpName (parameter_type);
357 type_name = TypeName.GetSignatureForError ();
359 string mod = GetModifierSignature (ModFlags);
361 return String.Concat (mod, ' ', type_name);
366 public static string GetModifierSignature (Modifier mod)
371 case Modifier.PARAMS:
375 case Modifier.ARGLIST:
382 public void IsClsCompliant ()
384 if (AttributeTester.IsClsCompliant (ExternalType ()))
387 Report.Error (3001, Location, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
390 public virtual void ApplyAttributes (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index)
393 builder = cb.DefineParameter (index, Attributes, Name);
395 builder = mb.DefineParameter (index, Attributes, Name);
397 if (OptAttributes != null)
398 OptAttributes.Emit (ec, this);
401 public override string[] ValidAttributeTargets {
403 return attribute_targets;
409 /// Represents the methods parameters
411 public class Parameters : ParameterData {
412 // Null object pattern
413 public Parameter [] FixedParameters;
414 public readonly bool HasArglist;
418 public static readonly Parameters EmptyReadOnlyParameters = new Parameters ();
419 static readonly Parameter ArgList = new ArglistParameter ();
421 public readonly TypeParameter[] TypeParameters;
423 private Parameters ()
425 FixedParameters = new Parameter[0];
426 types = new Type [0];
429 public Parameters (Parameter [] parameters)
431 if (parameters == null)
432 throw new ArgumentException ("Use EmptyReadOnlyPatameters");
434 FixedParameters = parameters;
435 count = parameters.Length;
438 public Parameters (Parameter[] parameters, bool has_arglist):
441 HasArglist = has_arglist;
452 return HasArglist ? count + 1 : count;
461 for (int i = 0; i < count; i++){
462 string base_name = FixedParameters [i].Name;
463 for (int j = i + 1; j < count; j++){
464 if (base_name != FixedParameters [j].Name)
467 Report.Error (100, FixedParameters [i].Location,
468 "The parameter name `{0}' is a duplicate", base_name);
477 /// Returns the paramenter information based on the name
479 public Parameter GetParameterByName (string name, out int idx)
488 foreach (Parameter par in FixedParameters){
489 if (par.Name == name){
498 public Parameter GetParameterByName (string name)
502 return GetParameterByName (name, out idx);
505 public bool Resolve (EmitContext ec)
510 types = new Type [count];
512 if (ec != null && !VerifyArgs ()){
518 for (int i = 0; i < FixedParameters.Length; ++i) {
519 p = FixedParameters [i];
520 if (!p.Resolve (ec)) {
524 types [i] = p.ExternalType ();
530 public CallingConventions CallingConvention
534 return CallingConventions.VarArgs;
536 return CallingConventions.Standard;
540 // Define each type attribute (in/out/ref) and
541 // the argument names.
542 public void ApplyAttributes (EmitContext ec, MethodBase builder)
547 MethodBuilder mb = builder as MethodBuilder;
548 ConstructorBuilder cb = builder as ConstructorBuilder;
550 for (int i = 0; i < FixedParameters.Length; i++) {
551 FixedParameters [i].ApplyAttributes (ec, mb, cb, i + 1);
555 public void VerifyClsCompliance ()
557 foreach (Parameter p in FixedParameters)
561 public string GetSignatureForError ()
563 StringBuilder sb = new StringBuilder ("(");
565 for (int i = 0; i < FixedParameters.Length; ++i) {
566 sb.Append (FixedParameters[i].GetSignatureForError ());
567 if (i < FixedParameters.Length - 1)
576 sb.Append ("__arglist");
581 return sb.ToString ();
584 public Type[] Types {
590 Parameter this [int pos]
593 if (pos >= count && (HasArglist || HasParams)) {
594 if (HasArglist && (pos == 0 || pos >= count))
599 return FixedParameters [pos];
603 #region ParameterData Members
605 public Type ParameterType (int pos)
607 return this [pos].ExternalType ();
610 public bool HasParams {
615 return FixedParameters [count - 1] is ParamsParameter;
619 public string ParameterName (int pos)
621 return this [pos].Name;
624 public string ParameterDesc (int pos)
626 return this [pos].GetSignatureForError ();
629 public Parameter.Modifier ParameterModifier (int pos)
631 return this [pos].ModFlags;