2 // parameter.cs: Parameter definition.
4 // Author: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
13 using System
.Reflection
;
14 using System
.Reflection
.Emit
;
15 using System
.Collections
;
17 namespace Mono
.CSharp
{
20 /// Abstract Base class for parameters of a method.
22 public abstract class ParameterBase
: Attributable
{
24 protected ParameterBuilder builder
;
26 public ParameterBase (Attributes attrs
)
31 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
33 if (a
.Type
== TypeManager
.marshal_as_attr_type
) {
34 UnmanagedMarshal marshal
= a
.GetMarshal (this);
35 if (marshal
!= null) {
36 builder
.SetMarshal (marshal
);
41 if (a
.Type
.IsSubclassOf (TypeManager
.security_attr_type
)) {
42 a
.Error_InvalidSecurityParent ();
46 builder
.SetCustomAttribute (cb
);
49 public override bool IsClsCompliaceRequired(DeclSpace ds
)
56 /// Class for applying custom attributes on the return type
58 public class ReturnParameter
: ParameterBase
{
59 public ReturnParameter (MethodBuilder mb
, Location location
):
63 builder
= mb
.DefineParameter (0, ParameterAttributes
.None
, "");
65 catch (ArgumentOutOfRangeException
) {
66 Report
.Warning (-28, location
, "The Microsoft .NET Runtime 1.x does not permit setting custom attributes on the return type");
70 public override void ApplyAttributeBuilder(Attribute a
, CustomAttributeBuilder cb
)
72 // This occurs after Warning -28
76 base.ApplyAttributeBuilder (a
, cb
);
79 public override AttributeTargets AttributeTargets
{
81 return AttributeTargets
.ReturnValue
;
88 public override string[] ValidAttributeTargets
{
96 /// Class for applying custom attributes on the implicit parameter type
97 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
99 public class ImplicitParameter
: ParameterBase
{
100 public ImplicitParameter (MethodBuilder mb
):
103 builder
= mb
.DefineParameter (1, ParameterAttributes
.None
, "");
106 public override AttributeTargets AttributeTargets
{
108 return AttributeTargets
.Parameter
;
115 public override string[] ValidAttributeTargets
{
123 /// Represents a single method parameter
126 //TODO: Add location member to this or base class for better error location and all methods simplification.
127 public class Parameter
: ParameterBase
{
129 public enum Modifier
: byte {
134 // This is a flag which says that it's either REF or OUT.
139 static string[] attribute_targets
= new string [] { "param" }
;
141 public Expression TypeName
;
142 public readonly Modifier ModFlags
;
143 public readonly string Name
;
146 public Parameter (Expression type
, string name
, Modifier mod
, Attributes attrs
)
154 public override void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
)
156 if (a
.Type
== TypeManager
.param_array_type
) {
157 Report
.Error (674, a
.Location
, "Do not use 'System.ParamArrayAttribute'. Use the 'params' keyword instead");
160 base.ApplyAttributeBuilder (a
, cb
);
164 // Resolve is used in method definitions
166 public bool Resolve (EmitContext ec
, Location l
)
168 TypeExpr texpr
= TypeName
.ResolveAsTypeTerminal (ec
, false);
172 parameter_type
= texpr
.ResolveType (ec
);
174 if (parameter_type
.IsAbstract
&& parameter_type
.IsSealed
) {
175 Report
.Error (721, l
, "'{0}': static types cannot be used as parameters", GetSignatureForError ());
179 if (parameter_type
== TypeManager
.void_type
){
180 Report
.Error (1536, l
, "`void' parameter is not permitted");
184 if ((ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0){
185 if (parameter_type
== TypeManager
.typed_reference_type
||
186 parameter_type
== TypeManager
.arg_iterator_type
){
187 Report
.Error (1601, l
,
188 "out or ref parameter can not be of type TypedReference or ArgIterator");
193 return parameter_type
!= null;
196 public Type
ExternalType ()
198 if ((ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
199 return TypeManager
.GetReferenceType (parameter_type
);
201 return parameter_type
;
204 public Type ParameterType
{
206 return parameter_type
;
210 public ParameterAttributes Attributes
{
212 int flags
= ((int) ModFlags
) & ~
((int) Parameter
.Modifier
.ISBYREF
);
213 switch ((Modifier
) flags
) {
215 return ParameterAttributes
.None
;
217 return ParameterAttributes
.None
;
219 return ParameterAttributes
.Out
;
220 case Modifier
.PARAMS
:
224 return ParameterAttributes
.None
;
228 public override AttributeTargets AttributeTargets
{
230 return AttributeTargets
.Parameter
;
235 /// Returns the signature for this parameter evaluating it on the
238 public string GetSignature (EmitContext ec
, Location loc
)
240 if (parameter_type
== null){
241 if (!Resolve (ec
, loc
))
245 return ExternalType ().FullName
;
248 public string GetSignatureForError ()
251 if (parameter_type
!= null)
252 typeName
= TypeManager
.CSharpName (parameter_type
);
253 else if (TypeName
.Type
!= null)
254 typeName
= TypeManager
.CSharpName (TypeName
.Type
);
256 typeName
= TypeName
.ToString ();
258 switch (ModFlags
& unchecked (~Modifier
.ISBYREF
)) {
260 return "out " + typeName
;
261 case Modifier
.PARAMS
:
262 return "params " + typeName
;
264 return "ref " + typeName
;
269 public void DefineParameter (EmitContext ec
, MethodBuilder mb
, ConstructorBuilder cb
, int index
, Location loc
)
271 ParameterAttributes par_attr
= Attributes
;
274 builder
= cb
.DefineParameter (index
, par_attr
, Name
);
276 builder
= mb
.DefineParameter (index
, par_attr
, Name
);
278 if (OptAttributes
!= null) {
279 OptAttributes
.Emit (ec
, this);
281 if (par_attr
== ParameterAttributes
.Out
){
282 if (OptAttributes
.Contains (TypeManager
.in_attribute_type
, ec
))
283 Report
.Error (36, loc
, "Can not use [In] attribute on out parameter");
288 public override string[] ValidAttributeTargets
{
290 return attribute_targets
;
296 /// Represents the methods parameters
298 public class Parameters
{
299 public Parameter
[] FixedParameters
;
300 public readonly Parameter ArrayParameter
;
301 public readonly bool HasArglist
;
306 static Parameters empty_parameters
;
308 public Parameters (Parameter
[] fixed_parameters
, Parameter array_parameter
, Location l
)
310 FixedParameters
= fixed_parameters
;
311 ArrayParameter
= array_parameter
;
315 public Parameters (Parameter
[] fixed_parameters
, bool has_arglist
, Location l
)
317 FixedParameters
= fixed_parameters
;
318 HasArglist
= has_arglist
;
323 /// This is used to reuse a set of empty parameters, because they
326 public static Parameters EmptyReadOnlyParameters
{
328 if (empty_parameters
== null)
329 empty_parameters
= new Parameters (null, null, Location
.Null
);
331 return empty_parameters
;
337 return (FixedParameters
== null) && (ArrayParameter
== null);
341 public void ComputeSignature (EmitContext ec
)
344 if (FixedParameters
!= null){
345 for (int i
= 0; i
< FixedParameters
.Length
; i
++){
346 Parameter par
= FixedParameters
[i
];
348 signature
+= par
.GetSignature (ec
, loc
);
352 // Note: as per the spec, the `params' arguments (ArrayParameter)
353 // are not used in the signature computation for a method
357 void Error_DuplicateParameterName (string name
)
360 100, loc
, "The parameter name `" + name
+ "' is a duplicate");
363 public bool VerifyArgs ()
368 if (FixedParameters
== null)
371 count
= FixedParameters
.Length
;
372 string array_par_name
= ArrayParameter
!= null ? ArrayParameter
.Name
: null;
374 for (i
= 0; i
< count
; i
++){
375 string base_name
= FixedParameters
[i
].Name
;
376 for (j
= i
+ 1; j
< count
; j
++){
377 if (base_name
!= FixedParameters
[j
].Name
)
379 Error_DuplicateParameterName (base_name
);
383 if (base_name
== array_par_name
){
384 Error_DuplicateParameterName (base_name
);
392 /// Returns the signature of the Parameters evaluated in
393 /// the @ec EmitContext
395 public string GetSignature (EmitContext ec
)
397 if (signature
== null){
399 ComputeSignature (ec
);
406 /// Returns the paramenter information based on the name
408 public Parameter
GetParameterByName (string name
, out int idx
)
413 if (FixedParameters
!= null){
414 foreach (Parameter par
in FixedParameters
){
415 if (par
.Name
== name
){
423 if (ArrayParameter
!= null){
424 if (name
== ArrayParameter
.Name
){
426 return ArrayParameter
;
433 public Parameter
GetParameterByName (string name
)
437 return GetParameterByName (name
, out idx
);
440 bool ComputeParameterTypes (EmitContext ec
)
442 int extra
= (ArrayParameter
!= null) ? 1 : 0;
446 if (FixedParameters
== null)
449 pc
= extra
+ FixedParameters
.Length
;
451 types
= new Type
[pc
];
454 FixedParameters
= null;
459 if (FixedParameters
!= null){
460 foreach (Parameter p
in FixedParameters
){
463 if (p
.Resolve (ec
, loc
))
464 t
= p
.ExternalType ();
474 if (ArrayParameter
.Resolve (ec
, loc
))
475 types
[i
] = ArrayParameter
.ExternalType ();
489 // This variant is used by Delegates, because they need to
490 // resolve/define names, instead of the plain LookupType
492 public bool ComputeAndDefineParameterTypes (EmitContext ec
)
494 bool old_type_resolving
= ec
.ResolvingTypeTree
;
495 ec
.ResolvingTypeTree
= true;
496 bool retval
= ComputeParameterTypes (ec
);
497 ec
.ResolvingTypeTree
= old_type_resolving
;
502 /// Returns the argument types as an array
504 static Type
[] no_types
= new Type
[0];
506 public Type
[] GetParameterInfo (EmitContext ec
)
511 if (FixedParameters
== null && ArrayParameter
== null)
514 if (ComputeParameterTypes (ec
) == false){
523 /// Returns the type of a given parameter, and stores in the `is_out'
524 /// boolean whether this is an out or ref parameter.
526 /// Note that the returned type will not contain any dereference in this
527 /// case (ie, you get "int" for a ref int instead of "int&"
529 public Type
GetParameterInfo (EmitContext ec
, int idx
, out Parameter
.Modifier mod
)
531 mod
= Parameter
.Modifier
.NONE
;
534 FixedParameters
= null;
538 if (FixedParameters
== null && ArrayParameter
== null)
542 if (ComputeParameterTypes (ec
) == false)
546 // If this is a request for the variable lenght arg.
548 int array_idx
= (FixedParameters
!= null ? FixedParameters
.Length
: 0);
549 if (idx
== array_idx
)
553 // Otherwise, it is a fixed parameter
555 Parameter p
= FixedParameters
[idx
];
558 if ((mod
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
)) != 0)
559 mod
|= Parameter
.Modifier
.ISBYREF
;
561 return p
.ParameterType
;
564 public CallingConventions
GetCallingConvention ()
567 return CallingConventions
.VarArgs
;
569 return CallingConventions
.Standard
;
573 // The method's attributes are passed in because we need to extract
574 // the "return:" attribute from there to apply on the return type
576 public void LabelParameters (EmitContext ec
,
580 // Define each type attribute (in/out/ref) and
581 // the argument names.
585 MethodBuilder mb
= builder
as MethodBuilder
;
586 ConstructorBuilder cb
= builder
as ConstructorBuilder
;
588 if (FixedParameters
!= null) {
589 for (i
= 0; i
< FixedParameters
.Length
; i
++) {
590 FixedParameters
[i
].DefineParameter (ec
, mb
, cb
, i
+ 1, loc
);
594 if (ArrayParameter
!= null){
596 Parameter array_param
= ArrayParameter
;
599 pb
= cb
.DefineParameter (
600 i
+ 1, array_param
.Attributes
,
603 pb
= mb
.DefineParameter (
604 i
+ 1, array_param
.Attributes
,
607 CustomAttributeBuilder a
= new CustomAttributeBuilder (
608 TypeManager
.cons_param_array_attribute
, new object [0]);
610 pb
.SetCustomAttribute (a
);