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