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