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
;
28 protected ParameterBase (Attributes attrs
)
33 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
35 if (a
.Type
== TypeManager
.marshal_as_attr_type
) {
36 UnmanagedMarshal marshal
= a
.GetMarshal (this);
37 if (marshal
!= null) {
38 builder
.SetMarshal (marshal
);
43 if (a
.Type
.IsSubclassOf (TypeManager
.security_attr_type
)) {
44 a
.Error_InvalidSecurityParent ();
48 builder
.SetCustomAttribute (cb
);
51 public override bool IsClsComplianceRequired()
58 /// Class for applying custom attributes on the return type
60 public class ReturnParameter
: ParameterBase
{
61 public ReturnParameter (MethodBuilder mb
, Location location
):
65 builder
= mb
.DefineParameter (0, ParameterAttributes
.None
, "");
67 catch (ArgumentOutOfRangeException
) {
68 Report
.RuntimeMissingSupport (location
, "custom attributes on the return type");
72 public override void ApplyAttributeBuilder(Attribute a
, CustomAttributeBuilder cb
)
74 if (a
.Type
== TypeManager
.cls_compliant_attribute_type
) {
75 Report
.Warning (3023, 1, a
.Location
, "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
78 // This occurs after Warning -28
82 base.ApplyAttributeBuilder (a
, cb
);
85 public override AttributeTargets AttributeTargets
{
87 return AttributeTargets
.ReturnValue
;
91 public override IResolveContext ResolveContext
{
93 throw new NotSupportedException ();
100 public override string[] ValidAttributeTargets
{
108 /// Class for applying custom attributes on the implicit parameter type
109 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
112 // TODO: should use more code from Parameter.ApplyAttributeBuilder
113 public class ImplicitParameter
: ParameterBase
{
114 public ImplicitParameter (MethodBuilder mb
):
117 builder
= mb
.DefineParameter (1, ParameterAttributes
.None
, "");
120 public override AttributeTargets AttributeTargets
{
122 return AttributeTargets
.Parameter
;
126 public override IResolveContext ResolveContext
{
128 throw new NotSupportedException ();
135 public override string[] ValidAttributeTargets
{
142 public class ParamsParameter
: Parameter
{
143 public ParamsParameter (Expression type
, string name
, Attributes attrs
, Location loc
):
144 base (type
, name
, Parameter
.Modifier
.PARAMS
, attrs
, loc
)
148 public override bool Resolve (IResolveContext ec
)
150 if (!base.Resolve (ec
))
153 if (!parameter_type
.IsArray
|| parameter_type
.GetArrayRank () != 1) {
154 Report
.Error (225, Location
, "The params parameter must be a single dimensional array");
160 public override void ApplyAttributes (MethodBuilder mb
, ConstructorBuilder cb
, int index
)
162 base.ApplyAttributes (mb
, cb
, index
);
164 CustomAttributeBuilder a
= new CustomAttributeBuilder (
165 TypeManager
.ConsParamArrayAttribute
, new object [0]);
167 builder
.SetCustomAttribute (a
);
171 public class ArglistParameter
: Parameter
{
172 // Doesn't have proper type because it's never choosed for better conversion
173 public ArglistParameter () :
174 base (typeof (ArglistParameter
), "", Parameter
.Modifier
.ARGLIST
, null, Location
.Null
)
178 public override bool Resolve (IResolveContext ec
)
183 public override string GetSignatureForError ()
190 /// Represents a single method parameter
192 public class Parameter
: ParameterBase
{
194 public enum Modifier
: byte {
196 REF
= REFMASK
| ISBYREF
,
197 OUT
= OUTMASK
| ISBYREF
,
199 // This is a flag which says that it's either REF or OUT.
206 static string[] attribute_targets
= new string [] { "param" }
;
208 public Expression TypeName
;
209 public readonly Modifier ModFlags
;
211 GenericConstraints constraints
;
212 protected Type parameter_type
;
213 public readonly Location Location
;
215 IResolveContext resolve_context
;
217 public Parameter (Expression type
, string name
, Modifier mod
, Attributes attrs
, Location loc
)
226 public Parameter (Type type
, string name
, Modifier mod
, Attributes attrs
, Location loc
)
231 parameter_type
= type
;
235 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
237 if (a
.Type
== TypeManager
.in_attribute_type
&& ModFlags
== Modifier
.OUT
) {
238 Report
.Error (36, a
.Location
, "An out parameter cannot have the `In' attribute");
242 if (a
.Type
== TypeManager
.param_array_type
) {
243 Report
.Error (674, a
.Location
, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
247 if (a
.Type
== TypeManager
.out_attribute_type
&& (ModFlags
& Modifier
.REF
) == Modifier
.REF
&&
248 !OptAttributes
.Contains (TypeManager
.in_attribute_type
)) {
249 Report
.Error (662, a
.Location
,
250 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
254 if (a
.Type
== TypeManager
.cls_compliant_attribute_type
) {
255 Report
.Warning (3022, 1, a
.Location
, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
258 // TypeManager.default_parameter_value_attribute_type is null if !NET_2_0
259 if (a
.Type
== TypeManager
.default_parameter_value_attribute_type
) {
260 object val
= a
.GetParameterDefaultValue ();
261 if (parameter_type
== TypeManager
.object_type
||
262 (val
== null && !TypeManager
.IsValueType (parameter_type
)) ||
263 (val
!= null && TypeManager
.TypeToCoreType (val
.GetType ()) == parameter_type
))
264 builder
.SetConstant (val
);
266 Report
.Error (1908, a
.Location
, "The type of the default value should match the type of the parameter");
270 base.ApplyAttributeBuilder (a
, cb
);
273 public override IResolveContext ResolveContext
{
275 return resolve_context
;
280 // Resolve is used in method definitions
282 public virtual bool Resolve (IResolveContext ec
)
284 if (parameter_type
!= null)
287 this.resolve_context
= ec
;
289 TypeExpr texpr
= TypeName
.ResolveAsTypeTerminal (ec
, false);
293 TypeParameterExpr tparam
= texpr
as TypeParameterExpr
;
295 constraints
= tparam
.TypeParameter
.Constraints
;
297 parameter_type
= texpr
.Type
;
299 if (parameter_type
.IsAbstract
&& parameter_type
.IsSealed
) {
300 Report
.Error (721, Location
, "`{0}': static types cannot be used as parameters", GetSignatureForError ());
304 if (parameter_type
== TypeManager
.void_type
){
305 Report
.Error (1536, Location
, "Invalid parameter type 'void'");
309 if ((ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0){
310 if (parameter_type
== TypeManager
.typed_reference_type
||
311 parameter_type
== TypeManager
.arg_iterator_type
){
312 Report
.Error (1601, Location
, "Method or delegate parameter cannot be of type `{0}'",
313 GetSignatureForError ());
321 public Type
ExternalType ()
323 if ((ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
324 return TypeManager
.GetReferenceType (parameter_type
);
326 return parameter_type
;
329 public Type ParameterType
{
331 return parameter_type
;
335 public GenericConstraints GenericConstraints
{
341 public ParameterAttributes Attributes
{
345 return ParameterAttributes
.None
;
347 return ParameterAttributes
.None
;
349 return ParameterAttributes
.Out
;
350 case Modifier
.PARAMS
:
354 return ParameterAttributes
.None
;
358 public static ParameterAttributes
GetParameterAttributes (Modifier mod
)
360 int flags
= ((int) mod
) & ~
((int) Parameter
.Modifier
.ISBYREF
);
361 switch ((Modifier
) flags
) {
363 return ParameterAttributes
.None
;
365 return ParameterAttributes
.None
;
367 return ParameterAttributes
.Out
;
368 case Modifier
.PARAMS
:
372 return ParameterAttributes
.None
;
375 public override AttributeTargets AttributeTargets
{
377 return AttributeTargets
.Parameter
;
381 public virtual string GetSignatureForError ()
384 if (parameter_type
!= null)
385 type_name
= TypeManager
.CSharpName (parameter_type
);
387 type_name
= TypeName
.GetSignatureForError ();
389 string mod
= GetModifierSignature (ModFlags
);
391 return String
.Concat (mod
, ' ', type_name
);
396 public static string GetModifierSignature (Modifier mod
)
401 case Modifier
.PARAMS
:
405 case Modifier
.ARGLIST
:
412 public void IsClsCompliant ()
414 if (AttributeTester
.IsClsCompliant (ExternalType ()))
417 Report
.Error (3001, Location
, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
420 public virtual void ApplyAttributes (MethodBuilder mb
, ConstructorBuilder cb
, int index
)
422 // TODO: It should use mb.DefineGenericParameters
425 builder
= cb
.DefineParameter (index
, Attributes
, Name
);
427 builder
= mb
.DefineParameter (index
, Attributes
, Name
);
429 if (OptAttributes
!= null)
430 OptAttributes
.Emit ();
433 public override string[] ValidAttributeTargets
{
435 return attribute_targets
;
441 /// Represents the methods parameters
443 public class Parameters
: ParameterData
{
444 // Null object pattern
445 public Parameter
[] FixedParameters
;
446 public readonly bool HasArglist
;
450 public static readonly Parameters EmptyReadOnlyParameters
= new Parameters ();
451 static readonly Parameter ArgList
= new ArglistParameter ();
453 public readonly TypeParameter
[] TypeParameters
;
455 private Parameters ()
457 FixedParameters
= new Parameter
[0];
458 types
= new Type
[0];
461 public Parameters (Parameter
[] parameters
, Type
[] types
)
463 FixedParameters
= parameters
;
465 count
= types
.Length
;
468 public Parameters (Parameter
[] parameters
)
470 if (parameters
== null)
471 throw new ArgumentException ("Use EmptyReadOnlyPatameters");
473 FixedParameters
= parameters
;
474 count
= parameters
.Length
;
477 public Parameters (Parameter
[] parameters
, bool has_arglist
):
480 HasArglist
= has_arglist
;
484 /// Use this method when you merge compiler generated argument with user arguments
486 public static Parameters
MergeGenerated (Parameters userParams
, params Parameter
[] compilerParams
)
488 Parameter
[] all_params
= new Parameter
[userParams
.count
+ compilerParams
.Length
];
489 Type
[] all_types
= new Type
[all_params
.Length
];
490 userParams
.FixedParameters
.CopyTo(all_params
, 0);
491 userParams
.Types
.CopyTo (all_types
, 0);
493 int last_filled
= userParams
.Count
;
494 foreach (Parameter p
in compilerParams
) {
495 for (int i
= 0; i
< last_filled
; ++i
) {
496 while (p
.Name
== all_params
[i
].Name
) {
497 p
.Name
= '_' + p
.Name
;
500 all_params
[last_filled
] = p
;
501 all_types
[last_filled
] = p
.ParameterType
;
505 return new Parameters (all_params
, all_types
);
516 return HasArglist
? count
+ 1 : count
;
525 for (int i
= 0; i
< count
; i
++){
526 string base_name
= FixedParameters
[i
].Name
;
527 for (int j
= i
+ 1; j
< count
; j
++){
528 if (base_name
!= FixedParameters
[j
].Name
)
531 Report
.Error (100, FixedParameters
[i
].Location
,
532 "The parameter name `{0}' is a duplicate", base_name
);
541 /// Returns the paramenter information based on the name
543 public Parameter
GetParameterByName (string name
, out int idx
)
552 foreach (Parameter par
in FixedParameters
){
553 if (par
.Name
== name
){
562 public Parameter
GetParameterByName (string name
)
566 return GetParameterByName (name
, out idx
);
569 public bool Resolve (IResolveContext ec
)
574 types
= new Type
[count
];
581 for (int i
= 0; i
< FixedParameters
.Length
; ++i
) {
582 p
= FixedParameters
[i
];
583 if (!p
.Resolve (ec
)) {
587 types
[i
] = p
.ExternalType ();
593 public CallingConventions CallingConvention
597 return CallingConventions
.VarArgs
;
599 return CallingConventions
.Standard
;
603 // Define each type attribute (in/out/ref) and
604 // the argument names.
605 public void ApplyAttributes (MethodBase builder
)
610 MethodBuilder mb
= builder
as MethodBuilder
;
611 ConstructorBuilder cb
= builder
as ConstructorBuilder
;
613 for (int i
= 0; i
< FixedParameters
.Length
; i
++) {
614 FixedParameters
[i
].ApplyAttributes (mb
, cb
, i
+ 1);
618 public void VerifyClsCompliance ()
620 foreach (Parameter p
in FixedParameters
)
624 public string GetSignatureForError ()
626 StringBuilder sb
= new StringBuilder ("(");
628 for (int i
= 0; i
< FixedParameters
.Length
; ++i
) {
629 sb
.Append (FixedParameters
[i
].GetSignatureForError ());
630 if (i
< FixedParameters
.Length
- 1)
638 sb
.Append ("__arglist");
642 return sb
.ToString ();
645 public Type
[] Types
{
651 Parameter
this [int pos
]
654 if (pos
>= count
&& (HasArglist
|| HasParams
)) {
655 if (HasArglist
&& (pos
== 0 || pos
>= count
))
660 return FixedParameters
[pos
];
664 #region ParameterData Members
666 public Type
ParameterType (int pos
)
668 return this [pos
].ExternalType ();
671 public bool HasParams
{
676 return FixedParameters
[count
- 1] is ParamsParameter
;
680 public string ParameterName (int pos
)
682 return this [pos
].Name
;
685 public string ParameterDesc (int pos
)
687 return this [pos
].GetSignatureForError ();
690 public Parameter
.Modifier
ParameterModifier (int pos
)
692 return this [pos
].ModFlags
;