This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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_T (-24, a.Location);
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_T (-28, location);
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                 protected 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                 protected 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                 // <summary>
154                 //   Resolve is used in method definitions
155                 // </summary>
156                 public bool Resolve (DeclSpace ds, Location l)
157                 {
158                         TypeExpr texpr = ds.ResolveTypeExpr (TypeName, false, l);
159                         if (texpr == null)
160                                 return false;
161
162                         TypeParameterExpr tparam = texpr as TypeParameterExpr;
163                         if (tparam != null)
164                                 constraints = tparam.TypeParameter.Constraints;
165
166                         parameter_type = ds.ResolveType (texpr, l);
167
168                         if (parameter_type == TypeManager.void_type){
169                                 Report.Error (1536, l, "`void' parameter is not permitted");
170                                 return false;
171                         }
172
173                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
174                                 if (parameter_type == TypeManager.typed_reference_type ||
175                                     parameter_type == TypeManager.arg_iterator_type){
176                                         Report.Error (1601, l,
177                                                       "out or ref parameter can not be of type TypedReference or ArgIterator");
178                                         return false;
179                                 }
180                         }
181                         
182                         return parameter_type != null;
183                 }
184
185                 public Type ExternalType ()
186                 {
187                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
188                                 return TypeManager.GetReferenceType (parameter_type);
189                         
190                         return parameter_type;
191                 }
192
193                 public Type ParameterType {
194                         get {
195                                 return parameter_type;
196                         }
197                 }
198
199                 public GenericConstraints GenericConstraints {
200                         get {
201                                 return constraints;
202                         }
203                 }
204                 
205                 public ParameterAttributes Attributes {
206                         get {
207                                 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
208                                 switch ((Modifier) flags) {
209                                 case Modifier.NONE:
210                                         return ParameterAttributes.None;
211                                 case Modifier.REF:
212                                         return ParameterAttributes.None;
213                                 case Modifier.OUT:
214                                         return ParameterAttributes.Out;
215                                 case Modifier.PARAMS:
216                                         return 0;
217                                 }
218                                 
219                                 return ParameterAttributes.None;
220                         }
221                 }
222                 
223                 public override AttributeTargets AttributeTargets {
224                         get {
225                                 return AttributeTargets.Parameter;
226                         }
227                 }
228
229                 /// <summary>
230                 ///   Returns the signature for this parameter evaluating it on the
231                 ///   @tc context
232                 /// </summary>
233                 public string GetSignature (DeclSpace ds, Location loc)
234                 {
235                         if (parameter_type == null){
236                                 if (!Resolve (ds, loc))
237                                         return null;
238                         }
239
240                         return ExternalType ().FullName;
241                 }
242
243                 public string GetSignatureForError ()
244                 {
245                         string typeName = TypeManager.CSharpName (parameter_type);
246                         switch (ModFlags & ~Modifier.ISBYREF) {
247                                 case Modifier.OUT:
248                                         return "out " + typeName;
249                                 case Modifier.PARAMS:
250                                         return "params " + typeName;
251                                 case Modifier.REF:
252                                         return "ref " + typeName;
253                         }
254                         return typeName;
255                 }
256
257                 public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
258                 {
259                         ParameterAttributes par_attr = Attributes;
260                                         
261                         if (mb == null)
262                                 builder = cb.DefineParameter (index, par_attr, Name);
263                         else 
264                                 builder = mb.DefineParameter (index, par_attr, Name);
265                                         
266                         if (OptAttributes != null) {
267                                 OptAttributes.Emit (ec, this);
268         
269                                 if (par_attr == ParameterAttributes.Out){
270                                         if (OptAttributes.Contains (TypeManager.in_attribute_type, ec))
271                                                 Report.Error (36, loc,  "Can not use [In] attribute on out parameter");
272                                 }
273                         }
274                 }
275
276                 protected override string[] ValidAttributeTargets {
277                         get {
278                                 return attribute_targets;
279                         }
280                 }
281         }
282
283         /// <summary>
284         ///   Represents the methods parameters
285         /// </summary>
286         public class Parameters {
287                 public Parameter [] FixedParameters;
288                 public readonly Parameter ArrayParameter;
289                 public readonly bool HasArglist;
290                 string signature;
291                 Type [] types;
292                 Location loc;
293                 
294                 static Parameters empty_parameters;
295                 
296                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
297                 {
298                         FixedParameters = fixed_parameters;
299                         ArrayParameter  = array_parameter;
300                         loc = l;
301                 }
302
303                 public Parameters (Parameter [] fixed_parameters, bool has_arglist, Location l)
304                 {
305                         FixedParameters = fixed_parameters;
306                         HasArglist = has_arglist;
307                         loc = l;
308                 }
309
310                 /// <summary>
311                 ///   This is used to reuse a set of empty parameters, because they
312                 ///   are common
313                 /// </summary>
314                 public static Parameters EmptyReadOnlyParameters {
315                         get {
316                                 if (empty_parameters == null)
317                                         empty_parameters = new Parameters (null, null, Location.Null);
318                         
319                                 return empty_parameters;
320                         }
321                 }
322                 
323                 public bool Empty {
324                         get {
325                                 return (FixedParameters == null) && (ArrayParameter == null);
326                         }
327                 }
328                 
329                 public void ComputeSignature (DeclSpace ds)
330                 {
331                         signature = "";
332                         if (FixedParameters != null){
333                                 for (int i = 0; i < FixedParameters.Length; i++){
334                                         Parameter par = FixedParameters [i];
335                                         
336                                         signature += par.GetSignature (ds, loc);
337                                 }
338                         }
339                         //
340                         // Note: as per the spec, the `params' arguments (ArrayParameter)
341                         // are not used in the signature computation for a method
342                         //
343                 }
344
345                 void Error_DuplicateParameterName (string name)
346                 {
347                         Report.Error (
348                                 100, loc, "The parameter name `" + name + "' is a duplicate");
349                 }
350                 
351                 public bool VerifyArgs ()
352                 {
353                         int count;
354                         int i, j;
355
356                         if (FixedParameters == null)
357                                 return true;
358                         
359                         count = FixedParameters.Length;
360                         string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
361                         for (i = 0; i < count; i++){
362                                 string base_name = FixedParameters [i].Name;
363                                 
364                                 for (j = i + 1; j < count; j++){
365                                         if (base_name != FixedParameters [j].Name)
366                                                 continue;
367                                         Error_DuplicateParameterName (base_name);
368                                         return false;
369                                 }
370
371                                 if (base_name == array_par_name){
372                                         Error_DuplicateParameterName (base_name);
373                                         return false;
374                                 }
375                         }
376                         return true;
377                 }
378                 
379                 /// <summary>
380                 ///    Returns the signature of the Parameters evaluated in
381                 ///    the @tc environment
382                 /// </summary>
383                 public string GetSignature (DeclSpace ds)
384                 {
385                         if (signature == null){
386                                 VerifyArgs ();
387                                 ComputeSignature (ds);
388                         }
389                         
390                         return signature;
391                 }
392                 
393                 /// <summary>
394                 ///    Returns the paramenter information based on the name
395                 /// </summary>
396                 public Parameter GetParameterByName (string name, out int idx)
397                 {
398                         idx = 0;
399                         int i = 0;
400
401                         if (FixedParameters != null){
402                                 foreach (Parameter par in FixedParameters){
403                                         if (par.Name == name){
404                                                 idx = i;
405                                                 return par;
406                                         }
407                                         i++;
408                                 }
409                         }
410
411                         if (ArrayParameter != null){
412                                 if (name == ArrayParameter.Name){
413                                         idx = i;
414                                         return ArrayParameter;
415                                 }
416                         }
417                         
418                         return null;
419                 }
420
421                 bool ComputeParameterTypes (DeclSpace ds)
422                 {
423                         int extra = (ArrayParameter != null) ? 1 : 0;
424                         int i = 0;
425                         int pc;
426
427                         if (FixedParameters == null)
428                                 pc = extra;
429                         else
430                                 pc = extra + FixedParameters.Length;
431
432                         types = new Type [pc];
433                         
434                         if (!VerifyArgs ()){
435                                 FixedParameters = null;
436                                 return false;
437                         }
438
439                         bool failed = false;
440                         if (FixedParameters != null){
441                                 foreach (Parameter p in FixedParameters){
442                                         Type t = null;
443                                         
444                                         if (p.Resolve (ds, loc))
445                                                 t = p.ExternalType ();
446                                         else
447                                                 failed = true;
448
449                                         types [i] = t;
450                                         i++;
451                                 }
452                         }
453                         
454                         if (extra > 0){
455                                 if (ArrayParameter.Resolve (ds, loc))
456                                         types [i] = ArrayParameter.ExternalType ();
457                                 else 
458                                         failed = true;
459                         }
460
461                         if (failed){
462                                 types = null;
463                                 return false;
464                         }
465
466                         return true;
467                 }
468
469                 //
470                 // This variant is used by Delegates, because they need to
471                 // resolve/define names, instead of the plain LookupType
472                 //
473                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
474                 {
475                         int extra = (ArrayParameter != null) ? 1 : 0;
476                         int i = 0;
477                         int pc;
478
479                         if (FixedParameters == null)
480                                 pc = extra;
481                         else
482                                 pc = extra + FixedParameters.Length;
483                         
484                         types = new Type [pc];
485                         
486                         if (!VerifyArgs ()){
487                                 FixedParameters = null;
488                                 return false;
489                         }
490
491                         bool ok_flag = true;
492                         
493                         if (FixedParameters != null){
494                                 foreach (Parameter p in FixedParameters){
495                                         Type t = null;
496                                         
497                                         if (p.Resolve (ds, loc))
498                                                 t = p.ExternalType ();
499                                         else
500                                                 ok_flag = false;
501                                         
502                                         types [i] = t;
503                                         i++;
504                                 }
505                         }
506                         
507                         if (extra > 0){
508                                 if (ArrayParameter.Resolve (ds, loc))
509                                         types [i] = ArrayParameter.ExternalType ();
510                                 else
511                                         ok_flag = false;
512                         }
513
514                         //
515                         // invalidate the cached types
516                         //
517                         if (!ok_flag){
518                                 types = null;
519                         }
520                         
521                         return ok_flag;
522                 }
523                 
524                 /// <summary>
525                 ///   Returns the argument types as an array
526                 /// </summary>
527                 static Type [] no_types = new Type [0];
528                 
529                 public Type [] GetParameterInfo (DeclSpace ds)
530                 {
531                         if (types != null)
532                                 return types;
533                         
534                         if (FixedParameters == null && ArrayParameter == null)
535                                 return no_types;
536
537                         if (ComputeParameterTypes (ds) == false){
538                                 types = null;
539                                 return null;
540                         }
541
542                         return types;
543                 }
544
545                 /// <summary>
546                 ///   Returns the type of a given parameter, and stores in the `is_out'
547                 ///   boolean whether this is an out or ref parameter.
548                 ///
549                 ///   Note that the returned type will not contain any dereference in this
550                 ///   case (ie, you get "int" for a ref int instead of "int&"
551                 /// </summary>
552                 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
553                 {
554                         mod = Parameter.Modifier.NONE;
555                         
556                         if (!VerifyArgs ()){
557                                 FixedParameters = null;
558                                 return null;
559                         }
560
561                         if (FixedParameters == null && ArrayParameter == null)
562                                 return null;
563                         
564                         if (types == null)
565                                 if (ComputeParameterTypes (ds) == false)
566                                         return null;
567
568                         //
569                         // If this is a request for the variable lenght arg.
570                         //
571                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
572                         if (idx == array_idx)
573                                 return types [idx];
574
575                         //
576                         // Otherwise, it is a fixed parameter
577                         //
578                         Parameter p = FixedParameters [idx];
579                         mod = p.ModFlags;
580
581                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
582                                 mod |= Parameter.Modifier.ISBYREF;
583
584                         return p.ParameterType;
585                 }
586
587                 public CallingConventions GetCallingConvention ()
588                 {
589                         if (HasArglist)
590                                 return CallingConventions.VarArgs;
591                         else
592                         return CallingConventions.Standard;
593                 }
594
595                 //
596                 // The method's attributes are passed in because we need to extract
597                 // the "return:" attribute from there to apply on the return type
598                 //
599                 public void LabelParameters (EmitContext ec,
600                         MethodBase builder,
601                         Location loc) {
602                         //
603                         // Define each type attribute (in/out/ref) and
604                         // the argument names.
605                         //
606                         int i = 0;
607                         
608                         MethodBuilder mb = builder as MethodBuilder;
609                         ConstructorBuilder cb = builder as ConstructorBuilder;
610
611                         if (FixedParameters != null) {
612                                 for (i = 0; i < FixedParameters.Length; i++) {
613                                         FixedParameters [i].DefineParameter (ec, mb, cb, i + 1, loc);
614                                 }
615                         }
616
617                         if (ArrayParameter != null){
618                                 ParameterBuilder pb;
619                                 Parameter array_param = ArrayParameter;
620
621                                 if (mb == null)
622                                         pb = cb.DefineParameter (
623                                                 i + 1, array_param.Attributes,
624                                                 array_param.Name);
625                                 else
626                                         pb = mb.DefineParameter (
627                                                 i + 1, array_param.Attributes,
628                                                 array_param.Name);
629                                         
630                                 CustomAttributeBuilder a = new CustomAttributeBuilder (
631                                         TypeManager.cons_param_array_attribute, new object [0]);
632                                 
633                                 pb.SetCustomAttribute (a);
634                         }
635                 }
636         }
637 }