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