**** Merged from MCS ****
[mono.git] / mcs / gmcs / parameter.cs
1 //
2 // parameter.cs: Parameter definition.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10 //
11 //
12 using System;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Collections;
16
17 namespace Mono.CSharp {
18
19         /// <summary>
20         ///   Abstract Base class for parameters of a method.
21         /// </summary>
22         public abstract class ParameterBase : Attributable {
23
24                 protected ParameterBuilder builder;
25
26                 public ParameterBase (Attributes attrs)
27                         : base (attrs)
28                 {
29                 }
30
31                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
32                 {
33                         if (a.Type == TypeManager.marshal_as_attr_type) {
34                                 UnmanagedMarshal marshal = a.GetMarshal ();
35                                 if (marshal != null) {
36                                         builder.SetMarshal (marshal);
37                                         return;
38                         }
39                                 Report.Warning (-24, a.Location, "The Microsoft Runtime cannot set this marshal info. Please use the Mono runtime instead.");
40                                 return;
41                         }
42
43                         builder.SetCustomAttribute (cb);
44                 }
45
46                 public override bool IsClsCompliaceRequired(DeclSpace ds)
47                 {
48                         return false;
49                                 }
50         }
51
52         /// <summary>
53         /// Class for applying custom attributes on the return type
54         /// </summary>
55         public class ReturnParameter: ParameterBase {
56                 public ReturnParameter (MethodBuilder mb, Location location):
57                         base (null)
58                 {
59                         try {
60                                 builder = mb.DefineParameter (0, ParameterAttributes.None, "");                 
61                         }
62                         catch (ArgumentOutOfRangeException) {
63                                 Report.Warning (-28, location, "The Microsoft .NET Runtime 1.x does not permit setting custom attributes on the return type");
64                         }
65                 }
66
67                 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
68                 {
69                         // This occurs after Warning -28
70                         if (builder == null)
71                                 return;
72
73                         base.ApplyAttributeBuilder (a, cb);
74                 }
75
76                 public override AttributeTargets AttributeTargets {
77                         get {
78                                 return AttributeTargets.ReturnValue;
79                         }
80                 }
81
82                 /// <summary>
83                 /// Is never called
84                 /// </summary>
85                 public override string[] ValidAttributeTargets {
86                         get {
87                                 return null;
88                         }
89                 }
90         }
91
92         /// <summary>
93        /// Class for applying custom attributes on the implicit parameter type
94        /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
95         /// </summary>
96        public class ImplicitParameter: ParameterBase {
97                public ImplicitParameter (MethodBuilder mb):
98                         base (null)
99                 {
100                         builder = mb.DefineParameter (1, ParameterAttributes.None, "");                 
101                 }
102
103                 public override AttributeTargets AttributeTargets {
104                         get {
105                                 return AttributeTargets.Parameter;
106                         }
107                 }
108
109                 /// <summary>
110                 /// Is never called
111                 /// </summary>
112                 public override string[] ValidAttributeTargets {
113                         get {
114                                 return null;
115                         }
116         }
117         }
118
119
120         /// <summary>
121         ///   Represents a single method parameter
122         /// </summary>
123
124         //TODO: Add location member to this or base class for better error location and all methods simplification.
125         public class Parameter : ParameterBase {
126                 [Flags]
127                 public enum Modifier : byte {
128                         NONE    = 0,
129                         REF     = 1,
130                         OUT     = 2,
131                         PARAMS  = 4,
132                         // This is a flag which says that it's either REF or OUT.
133                         ISBYREF = 8,
134                         ARGLIST = 16
135                 }
136
137                 static string[] attribute_targets = new string [] { "param" };
138
139                 public readonly Expression TypeName;
140                 public readonly Modifier ModFlags;
141                 public readonly string Name;
142                 GenericConstraints constraints;
143                 Type parameter_type;
144                 
145                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
146                         : base (attrs)
147                 {
148                         Name = name;
149                         ModFlags = mod;
150                         TypeName = type;
151                 }
152
153                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
154                 {
155                         if (a.Type == TypeManager.param_array_type) {
156                                 Report.Error (674, a.Location, "Do not use 'System.ParamArrayAttribute'. Use the 'params' keyword instead");
157                                 return;
158                         }
159                         base.ApplyAttributeBuilder (a, cb);
160                 }
161
162                 // <summary>
163                 //   Resolve is used in method definitions
164                 // </summary>
165                 public bool Resolve (DeclSpace ds, Location l)
166                 {
167                         TypeExpr texpr = ds.ResolveTypeExpr (TypeName, false, l);
168                         if (texpr == null)
169                                 return false;
170
171                         TypeParameterExpr tparam = texpr as TypeParameterExpr;
172                         if (tparam != null)
173                                 constraints = tparam.TypeParameter.Constraints;
174
175                         parameter_type = ds.ResolveType (texpr, l);
176
177                         if (parameter_type.IsAbstract && parameter_type.IsSealed) {
178                                 Report.Error (721, l, "'{0}': static types cannot be used as parameters", GetSignatureForError ());
179                                 return false;
180                         }
181
182                         if (parameter_type == TypeManager.void_type){
183                                 Report.Error (1536, l, "`void' parameter is not permitted");
184                                 return false;
185                         }
186
187                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
188                                 if (parameter_type == TypeManager.typed_reference_type ||
189                                     parameter_type == TypeManager.arg_iterator_type){
190                                         Report.Error (1601, l,
191                                                       "out or ref parameter can not be of type TypedReference or ArgIterator");
192                                         return false;
193                                 }
194                         }
195                         
196                         return parameter_type != null;
197                 }
198
199                 public Type ExternalType ()
200                 {
201                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
202                                 return TypeManager.GetReferenceType (parameter_type);
203                         
204                         return parameter_type;
205                 }
206
207                 public Type ParameterType {
208                         get {
209                                 return parameter_type;
210                         }
211                 }
212
213                 public GenericConstraints GenericConstraints {
214                         get {
215                                 return constraints;
216                         }
217                 }
218                 
219                 public ParameterAttributes Attributes {
220                         get {
221                                 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
222                                 switch ((Modifier) flags) {
223                                 case Modifier.NONE:
224                                         return ParameterAttributes.None;
225                                 case Modifier.REF:
226                                         return ParameterAttributes.None;
227                                 case Modifier.OUT:
228                                         return ParameterAttributes.Out;
229                                 case Modifier.PARAMS:
230                                         return 0;
231                                 }
232                                 
233                                 return ParameterAttributes.None;
234                         }
235                 }
236                 
237                 public override AttributeTargets AttributeTargets {
238                         get {
239                                 return AttributeTargets.Parameter;
240                         }
241                 }
242
243                 /// <summary>
244                 ///   Returns the signature for this parameter evaluating it on the
245                 ///   @tc context
246                 /// </summary>
247                 public string GetSignature (DeclSpace ds, Location loc)
248                 {
249                         if (parameter_type == null){
250                                 if (!Resolve (ds, loc))
251                                         return null;
252                         }
253
254                         return ExternalType ().FullName;
255                 }
256
257                 public string GetSignatureForError ()
258                 {
259                         string typeName = TypeManager.CSharpName (parameter_type);
260                         switch (ModFlags & ~Modifier.ISBYREF) {
261                                 case Modifier.OUT:
262                                         return "out " + typeName;
263                                 case Modifier.PARAMS:
264                                         return "params " + typeName;
265                                 case Modifier.REF:
266                                         return "ref " + typeName;
267                         }
268                         return typeName;
269                 }
270
271                 public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
272                 {
273                         ParameterAttributes par_attr = Attributes;
274                                         
275                         if (mb == null)
276                                 builder = cb.DefineParameter (index, par_attr, Name);
277                         else 
278                                 builder = mb.DefineParameter (index, par_attr, Name);
279                                         
280                         if (OptAttributes != null) {
281                                 OptAttributes.Emit (ec, this);
282         
283                                 if (par_attr == ParameterAttributes.Out){
284                                         if (OptAttributes.Contains (TypeManager.in_attribute_type, ec))
285                                                 Report.Error (36, loc,  "Can not use [In] attribute on out parameter");
286                                 }
287                         }
288                 }
289
290                 public override string[] ValidAttributeTargets {
291                         get {
292                                 return attribute_targets;
293                         }
294                 }
295         }
296
297         /// <summary>
298         ///   Represents the methods parameters
299         /// </summary>
300         public class Parameters {
301                 public Parameter [] FixedParameters;
302                 public readonly Parameter ArrayParameter;
303                 public readonly bool HasArglist;
304                 string signature;
305                 Type [] types;
306                 Location loc;
307                 
308                 static Parameters empty_parameters;
309                 
310                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
311                 {
312                         FixedParameters = fixed_parameters;
313                         ArrayParameter  = array_parameter;
314                         loc = l;
315                 }
316
317                 public Parameters (Parameter [] fixed_parameters, bool has_arglist, Location l)
318                 {
319                         FixedParameters = fixed_parameters;
320                         HasArglist = has_arglist;
321                         loc = l;
322                 }
323
324                 /// <summary>
325                 ///   This is used to reuse a set of empty parameters, because they
326                 ///   are common
327                 /// </summary>
328                 public static Parameters EmptyReadOnlyParameters {
329                         get {
330                                 if (empty_parameters == null)
331                                         empty_parameters = new Parameters (null, null, Location.Null);
332                         
333                                 return empty_parameters;
334                         }
335                 }
336                 
337                 public bool Empty {
338                         get {
339                                 return (FixedParameters == null) && (ArrayParameter == null);
340                         }
341                 }
342                 
343                 public void ComputeSignature (DeclSpace ds)
344                 {
345                         signature = "";
346                         if (FixedParameters != null){
347                                 for (int i = 0; i < FixedParameters.Length; i++){
348                                         Parameter par = FixedParameters [i];
349                                         
350                                         signature += par.GetSignature (ds, loc);
351                                 }
352                         }
353                         //
354                         // Note: as per the spec, the `params' arguments (ArrayParameter)
355                         // are not used in the signature computation for a method
356                         //
357                 }
358
359                 void Error_DuplicateParameterName (string name)
360                 {
361                         Report.Error (
362                                 100, loc, "The parameter name `" + name + "' is a duplicate");
363                 }
364                 
365                 public bool VerifyArgs ()
366                 {
367                         int count;
368                         int i, j;
369
370                         if (FixedParameters == null)
371                                 return true;
372                         
373                         count = FixedParameters.Length;
374                         string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
375                         for (i = 0; i < count; i++){
376                                 string base_name = FixedParameters [i].Name;
377                                 
378                                 for (j = i + 1; j < count; j++){
379                                         if (base_name != FixedParameters [j].Name)
380                                                 continue;
381                                         Error_DuplicateParameterName (base_name);
382                                         return false;
383                                 }
384
385                                 if (base_name == array_par_name){
386                                         Error_DuplicateParameterName (base_name);
387                                         return false;
388                                 }
389                         }
390                         return true;
391                 }
392                 
393                 /// <summary>
394                 ///    Returns the signature of the Parameters evaluated in
395                 ///    the @tc environment
396                 /// </summary>
397                 public string GetSignature (DeclSpace ds)
398                 {
399                         if (signature == null){
400                                 VerifyArgs ();
401                                 ComputeSignature (ds);
402                         }
403                         
404                         return signature;
405                 }
406                 
407                 /// <summary>
408                 ///    Returns the paramenter information based on the name
409                 /// </summary>
410                 public Parameter GetParameterByName (string name, out int idx)
411                 {
412                         idx = 0;
413                         int i = 0;
414
415                         if (FixedParameters != null){
416                                 foreach (Parameter par in FixedParameters){
417                                         if (par.Name == name){
418                                                 idx = i;
419                                                 return par;
420                                         }
421                                         i++;
422                                 }
423                         }
424
425                         if (ArrayParameter != null){
426                                 if (name == ArrayParameter.Name){
427                                         idx = i;
428                                         return ArrayParameter;
429                                 }
430                         }
431                         
432                         return null;
433                 }
434
435                 bool ComputeParameterTypes (DeclSpace ds)
436                 {
437                         int extra = (ArrayParameter != null) ? 1 : 0;
438                         int i = 0;
439                         int pc;
440
441                         if (FixedParameters == null)
442                                 pc = extra;
443                         else
444                                 pc = extra + FixedParameters.Length;
445
446                         types = new Type [pc];
447                         
448                         if (!VerifyArgs ()){
449                                 FixedParameters = null;
450                                 return false;
451                         }
452
453                         bool failed = false;
454                         if (FixedParameters != null){
455                                 foreach (Parameter p in FixedParameters){
456                                         Type t = null;
457                                         
458                                         if (p.Resolve (ds, loc))
459                                                 t = p.ExternalType ();
460                                         else
461                                                 failed = true;
462
463                                         types [i] = t;
464                                         i++;
465                                 }
466                         }
467                         
468                         if (extra > 0){
469                                 if (ArrayParameter.Resolve (ds, loc))
470                                         types [i] = ArrayParameter.ExternalType ();
471                                 else 
472                                         failed = true;
473                         }
474
475                         if (failed){
476                                 types = null;
477                                 return false;
478                         }
479
480                         return true;
481                 }
482
483                 //
484                 // This variant is used by Delegates, because they need to
485                 // resolve/define names, instead of the plain LookupType
486                 //
487                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
488                 {
489                         int extra = (ArrayParameter != null) ? 1 : 0;
490                         int i = 0;
491                         int pc;
492
493                         if (FixedParameters == null)
494                                 pc = extra;
495                         else
496                                 pc = extra + FixedParameters.Length;
497                         
498                         types = new Type [pc];
499                         
500                         if (!VerifyArgs ()){
501                                 FixedParameters = null;
502                                 return false;
503                         }
504
505                         bool ok_flag = true;
506                         
507                         if (FixedParameters != null){
508                                 foreach (Parameter p in FixedParameters){
509                                         Type t = null;
510                                         
511                                         if (p.Resolve (ds, loc))
512                                                 t = p.ExternalType ();
513                                         else
514                                                 ok_flag = false;
515                                         
516                                         types [i] = t;
517                                         i++;
518                                 }
519                         }
520                         
521                         if (extra > 0){
522                                 if (ArrayParameter.Resolve (ds, loc))
523                                         types [i] = ArrayParameter.ExternalType ();
524                                 else
525                                         ok_flag = false;
526                         }
527
528                         //
529                         // invalidate the cached types
530                         //
531                         if (!ok_flag){
532                                 types = null;
533                         }
534                         
535                         return ok_flag;
536                 }
537                 
538                 /// <summary>
539                 ///   Returns the argument types as an array
540                 /// </summary>
541                 static Type [] no_types = new Type [0];
542                 
543                 public Type [] GetParameterInfo (DeclSpace ds)
544                 {
545                         if (types != null)
546                                 return types;
547                         
548                         if (FixedParameters == null && ArrayParameter == null)
549                                 return no_types;
550
551                         if (ComputeParameterTypes (ds) == false){
552                                 types = null;
553                                 return null;
554                         }
555
556                         return types;
557                 }
558
559                 /// <summary>
560                 ///   Returns the type of a given parameter, and stores in the `is_out'
561                 ///   boolean whether this is an out or ref parameter.
562                 ///
563                 ///   Note that the returned type will not contain any dereference in this
564                 ///   case (ie, you get "int" for a ref int instead of "int&"
565                 /// </summary>
566                 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
567                 {
568                         mod = Parameter.Modifier.NONE;
569                         
570                         if (!VerifyArgs ()){
571                                 FixedParameters = null;
572                                 return null;
573                         }
574
575                         if (FixedParameters == null && ArrayParameter == null)
576                                 return null;
577                         
578                         if (types == null)
579                                 if (ComputeParameterTypes (ds) == false)
580                                         return null;
581
582                         //
583                         // If this is a request for the variable lenght arg.
584                         //
585                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
586                         if (idx == array_idx)
587                                 return types [idx];
588
589                         //
590                         // Otherwise, it is a fixed parameter
591                         //
592                         Parameter p = FixedParameters [idx];
593                         mod = p.ModFlags;
594
595                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
596                                 mod |= Parameter.Modifier.ISBYREF;
597
598                         return p.ParameterType;
599                 }
600
601                 public CallingConventions GetCallingConvention ()
602                 {
603                         if (HasArglist)
604                                 return CallingConventions.VarArgs;
605                         else
606                         return CallingConventions.Standard;
607                 }
608
609                 //
610                 // The method's attributes are passed in because we need to extract
611                 // the "return:" attribute from there to apply on the return type
612                 //
613                 public void LabelParameters (EmitContext ec,
614                         MethodBase builder,
615                         Location loc) {
616                         //
617                         // Define each type attribute (in/out/ref) and
618                         // the argument names.
619                         //
620                         int i = 0;
621                         
622                         MethodBuilder mb = builder as MethodBuilder;
623                         ConstructorBuilder cb = builder as ConstructorBuilder;
624
625                         if (FixedParameters != null) {
626                                 for (i = 0; i < FixedParameters.Length; i++) {
627                                         FixedParameters [i].DefineParameter (ec, mb, cb, i + 1, loc);
628                                 }
629                         }
630
631                         if (ArrayParameter != null){
632                                 ParameterBuilder pb;
633                                 Parameter array_param = ArrayParameter;
634
635                                 if (mb == null)
636                                         pb = cb.DefineParameter (
637                                                 i + 1, array_param.Attributes,
638                                                 array_param.Name);
639                                 else
640                                         pb = mb.DefineParameter (
641                                                 i + 1, array_param.Attributes,
642                                                 array_param.Name);
643                                         
644                                 CustomAttributeBuilder a = new CustomAttributeBuilder (
645                                         TypeManager.cons_param_array_attribute, new object [0]);
646                                 
647                                 pb.SetCustomAttribute (a);
648                         }
649                 }
650         }
651 }