merge -r 53370:58178
[mono.git] / mcs / mcs / 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                 protected Type parameter_type;
202
203                 EmitContext ec;  // because ApplyAtrribute doesn't have ec
204                 
205                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Location loc)
206                         : base (attrs, loc)
207                 {
208                         Name = name;
209                         ModFlags = mod;
210                         TypeName = type;
211                 }
212
213                 public Parameter (Type type, string name, Modifier mod, Attributes attrs, Location loc)
214                         : base (attrs, loc)
215                 {
216                         Name = name;
217                         ModFlags = mod;
218                         parameter_type = type;
219                 }
220
221                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
222                 {
223                         if (a.Type == TypeManager.in_attribute_type && ModFlags == Modifier.OUT) {
224                                 Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
225                                 return;
226                         }
227
228                         if (a.Type == TypeManager.param_array_type) {
229                                 Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
230                                 return;
231                         }
232
233                         if (a.Type == TypeManager.out_attribute_type && (ModFlags & Modifier.REF) == Modifier.REF &&
234                             !OptAttributes.Contains (TypeManager.in_attribute_type, ec)) {
235                                 Report.Error (662, a.Location,
236                                         "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
237                                 return;
238                         }
239
240                         if (a.Type == TypeManager.cls_compliant_attribute_type) {
241                                 Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
242                         }
243
244                         base.ApplyAttributeBuilder (a, cb);
245                 }
246
247                 // <summary>
248                 //   Resolve is used in method definitions
249                 // </summary>
250                 public virtual bool Resolve (EmitContext ec)
251                 {
252                         if (parameter_type != null)
253                                 return true;
254
255                         this.ec = ec;
256
257                         TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec, false);
258                         if (texpr == null)
259                                 return false;
260
261                         parameter_type = texpr.ResolveType (ec);
262                         
263                         if (parameter_type.IsAbstract && parameter_type.IsSealed) {
264                                 Report.Error (721, Location, "`{0}': static types cannot be used as parameters", GetSignatureForError ());
265                                 return false;
266                         }
267
268                         if (parameter_type == TypeManager.void_type){
269                                 Report.Error (1536, Location, "Invalid parameter type 'void'");
270                                 return false;
271                         }
272
273                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
274                                 if (parameter_type == TypeManager.typed_reference_type ||
275                                     parameter_type == TypeManager.arg_iterator_type){
276                                         Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
277                                                 GetSignatureForError ());
278                                         return false;
279                                 }
280                         }
281                         
282                         return true;
283                 }
284
285                 public Type ExternalType ()
286                 {
287                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
288                                 return TypeManager.GetReferenceType (parameter_type);
289                         
290                         return parameter_type;
291                 }
292
293                 public Type ParameterType {
294                         get {
295                                 return parameter_type;
296                         }
297                 }
298                 
299                 public ParameterAttributes Attributes {
300                         get {
301                                 switch (ModFlags) {
302                                 case Modifier.NONE:
303                                         return ParameterAttributes.None;
304                                 case Modifier.REF:
305                                         return ParameterAttributes.None;
306                                 case Modifier.OUT:
307                                         return ParameterAttributes.Out;
308                                 case Modifier.PARAMS:
309                                         return 0;
310                                 }
311                                 
312                                 return ParameterAttributes.None;
313                         }
314                 }
315                 
316                 public override AttributeTargets AttributeTargets {
317                         get {
318                                 return AttributeTargets.Parameter;
319                         }
320                 }
321
322                 public virtual string GetSignatureForError ()
323                 {
324                         string type_name;
325                         if (parameter_type != null)
326                                 type_name = TypeManager.CSharpName (parameter_type);
327                         else
328                                 type_name = TypeName.GetSignatureForError ();
329
330                         string mod = GetModifierSignature (ModFlags);
331                         if (mod.Length > 0)
332                                 return String.Concat (mod, ' ', type_name);
333
334                         return type_name;
335                 }
336
337                 public static string GetModifierSignature (Modifier mod)
338                 {
339                         switch (mod) {
340                                 case Modifier.OUT:
341                                         return "out";
342                                 case Modifier.PARAMS:
343                                         return "params";
344                                 case Modifier.REF:
345                                         return "ref";
346                                 case Modifier.ARGLIST:
347                                         return "__arglist";
348                                 default:
349                                         return "";
350                         }
351                 }
352
353                 public void IsClsCompliant ()
354                 {
355                         if (AttributeTester.IsClsCompliant (ExternalType ()))
356                                 return;
357
358                         Report.Error (3001, Location, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
359                 }
360
361                 public virtual void ApplyAttributes (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index)
362                 {
363                         if (mb == null)
364                                 builder = cb.DefineParameter (index, Attributes, Name);
365                         else 
366                                 builder = mb.DefineParameter (index, Attributes, Name);
367                 
368                         if (OptAttributes != null)
369                                 OptAttributes.Emit (ec, this);
370                 }
371
372                 public override string[] ValidAttributeTargets {
373                         get {
374                                 return attribute_targets;
375                         }
376                 }
377         }
378
379         /// <summary>
380         ///   Represents the methods parameters
381         /// </summary>
382         public class Parameters : ParameterData {
383                 // Null object pattern
384                 public Parameter [] FixedParameters;
385                 public readonly bool HasArglist;
386                 Type [] types;
387                 int count;
388
389                 public static readonly Parameters EmptyReadOnlyParameters = new Parameters ();
390                 static readonly Parameter ArgList = new ArglistParameter ();
391
392                 private Parameters ()
393                 {
394                         FixedParameters = new Parameter[0];
395                         types = new Type [0];
396                 }
397                 
398                 public Parameters (Parameter [] parameters)
399                 {
400                         if (parameters == null)
401                                 throw new ArgumentException ("Use EmptyReadOnlyPatameters");
402
403                         FixedParameters = parameters;
404                         count = parameters.Length;
405                 }
406
407                 public Parameters (Parameter[] parameters, bool has_arglist):
408                         this (parameters)
409                 {
410                         HasArglist = has_arglist;
411                 }
412
413                 public bool Empty {
414                         get {
415                                 return count == 0;
416                         }
417                 }
418
419                 public int Count {
420                         get {
421                                 return HasArglist ? count + 1 : count;
422                         }
423                 }
424
425                 bool VerifyArgs ()
426                 {
427                         if (count < 2)
428                                 return true;
429
430                         for (int i = 0; i < count; i++){
431                                 string base_name = FixedParameters [i].Name;
432                                 for (int j = i + 1; j < count; j++){
433                                         if (base_name != FixedParameters [j].Name)
434                                                 continue;
435
436                                         Report.Error (100, FixedParameters [i].Location,
437                                                 "The parameter name `{0}' is a duplicate", base_name);
438                                         return false;
439                                 }
440                         }
441                         return true;
442                 }
443                 
444                 
445                 /// <summary>
446                 ///    Returns the paramenter information based on the name
447                 /// </summary>
448                 public Parameter GetParameterByName (string name, out int idx)
449                 {
450                         idx = 0;
451
452                         if (count == 0)
453                                 return null;
454
455                         int i = 0;
456
457                         foreach (Parameter par in FixedParameters){
458                                 if (par.Name == name){
459                                         idx = i;
460                                         return par;
461                                 }
462                                 i++;
463                         }
464                         return null;
465                 }
466
467                 public Parameter GetParameterByName (string name)
468                 {
469                         int idx;
470
471                         return GetParameterByName (name, out idx);
472                 }
473                 
474                 public bool Resolve (EmitContext ec)
475                 {
476                         if (types != null)
477                                 return true;
478
479                         types = new Type [count];
480                         
481                         if (ec != null && !VerifyArgs ()){
482                                 return false;
483                         }
484
485                         bool ok = true;
486                         Parameter p;
487                         for (int i = 0; i < FixedParameters.Length; ++i) {
488                                 p = FixedParameters [i];
489                                 if (!p.Resolve (ec)) {
490                                         ok = false;
491                                         continue;
492                                 }
493                                 types [i] = p.ExternalType ();
494                         }
495
496                         return ok;
497                 }
498
499                 public CallingConventions CallingConvention
500                 {
501                         get {
502                                 if (HasArglist)
503                                         return CallingConventions.VarArgs;
504                                 else
505                                         return CallingConventions.Standard;
506                         }
507                 }
508
509                 // Define each type attribute (in/out/ref) and
510                 // the argument names.
511                 public void ApplyAttributes (EmitContext ec, MethodBase builder)
512                 {
513                         if (count == 0)
514                                 return;
515
516                         MethodBuilder mb = builder as MethodBuilder;
517                         ConstructorBuilder cb = builder as ConstructorBuilder;
518
519                         for (int i = 0; i < FixedParameters.Length; i++) {
520                                 FixedParameters [i].ApplyAttributes (ec, mb, cb, i + 1);
521                         }
522                 }
523
524                 public void VerifyClsCompliance ()
525                 {
526                         foreach (Parameter p in FixedParameters)
527                                 p.IsClsCompliant ();
528                 }
529
530                 public string GetSignatureForError ()
531                 {
532                         StringBuilder sb = new StringBuilder ("(");
533                         if (count > 0) {
534                                 for (int i = 0; i < FixedParameters.Length; ++i) {
535                                         sb.Append (FixedParameters[i].GetSignatureForError ());
536                                         if (i < FixedParameters.Length - 1)
537                                                 sb.Append (", ");
538                                 }
539                         }
540
541                         if (HasArglist) {
542                                 if (HasArglist) {
543                                         if (sb.Length > 1)
544                                                 sb.Append (", ");
545                                         sb.Append ("__arglist");
546                                 }
547                         }
548
549                         sb.Append (')');
550                         return sb.ToString ();
551                 }
552
553                 public Type[] Types {
554                         get {
555                                 return types;
556                         }
557                 }
558
559                 Parameter this [int pos]
560                 {
561                         get {
562                                 if (pos >= count && (HasArglist || HasParams)) {
563                                         if (HasArglist && (pos == 0 || pos >= count))
564                                                 return ArgList;
565                                         pos = count - 1;
566                                 }
567
568                                 return FixedParameters [pos];
569                         }
570                 }
571
572                 #region ParameterData Members
573
574                 public Type ParameterType (int pos)
575                 {
576                         return this [pos].ExternalType ();
577                 }
578
579                 public bool HasParams {
580                         get {
581                                 if (count == 0)
582                                         return false;
583
584                                 return FixedParameters [count - 1] is ParamsParameter;
585                         }
586                 }
587
588                 public string ParameterName (int pos)
589                 {
590                         return this [pos].Name;
591                 }
592
593                 public string ParameterDesc (int pos)
594                 {
595                         return this [pos].GetSignatureForError ();
596                 }
597
598                 public Parameter.Modifier ParameterModifier (int pos)
599                 {
600                         return this [pos].ModFlags;
601                 }
602
603                 #endregion
604         }
605 }