**** Merged from HEAD ****
[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
20         /// <summary>
21         ///   Represents a single method parameter
22         /// </summary>
23         public class Parameter {
24                 [Flags]
25                 public enum Modifier : byte {
26                         NONE    = 0,
27                         REF     = 1,
28                         OUT     = 2,
29                         PARAMS  = 4,
30                         // This is a flag which says that it's either REF or OUT.
31                         ISBYREF = 8
32                 }
33
34                 public readonly Expression TypeName;
35                 public readonly Modifier ModFlags;
36                 public Attributes OptAttributes;
37                 public readonly string Name;
38                 public Type parameter_type;
39                 
40                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
41                 {
42                         Name = name;
43                         ModFlags = mod;
44                         TypeName = type;
45                         OptAttributes = attrs;
46                 }
47
48                 // <summary>
49                 //   Resolve is used in method definitions
50                 // </summary>
51                 public bool Resolve (DeclSpace ds, Location l)
52                 {
53                         parameter_type = ds.ResolveType (TypeName, false, l);
54
55                         if (parameter_type == TypeManager.void_type){
56                                 Report.Error (1536, l, "`void' parameter is not permitted");
57                                 return false;
58                         }
59
60                         return parameter_type != null;
61                 }
62
63                 public Type ExternalType ()
64                 {
65                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
66                                 return TypeManager.GetReferenceType (parameter_type);
67                         
68                         return parameter_type;
69                 }
70
71                 public Type ParameterType {
72                         get {
73                                 return parameter_type;
74                         }
75                 }
76                 
77                 public ParameterAttributes Attributes {
78                         get {
79                                 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
80                                 switch ((Modifier) flags) {
81                                 case Modifier.NONE:
82                                         return ParameterAttributes.None;
83                                 case Modifier.REF:
84                                         return ParameterAttributes.None;
85                                 case Modifier.OUT:
86                                         return ParameterAttributes.Out;
87                                 case Modifier.PARAMS:
88                                         return 0;
89                                 }
90                                 
91                                 return ParameterAttributes.None;
92                         }
93                 }
94                 
95                 /// <summary>
96                 ///   Returns the signature for this parameter evaluating it on the
97                 ///   @tc context
98                 /// </summary>
99                 public string GetSignature (DeclSpace ds, Location loc)
100                 {
101                         if (parameter_type == null){
102                                 if (!Resolve (ds, loc))
103                                         return null;
104                         }
105
106                         return ExternalType ().FullName;
107                 }
108         }
109
110         /// <summary>
111         ///   Represents the methods parameters
112         /// </summary>
113         public class Parameters {
114                 public Parameter [] FixedParameters;
115                 public readonly Parameter ArrayParameter;
116                 string signature;
117                 Type [] types;
118                 Location loc;
119                 
120                 static Parameters empty_parameters;
121                 
122                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
123                 {
124                         FixedParameters = fixed_parameters;
125                         ArrayParameter  = array_parameter;
126                         loc = l;
127                 }
128
129                 /// <summary>
130                 ///   This is used to reuse a set of empty parameters, because they
131                 ///   are common
132                 /// </summary>
133                 public static Parameters EmptyReadOnlyParameters {
134                         get {
135                                 if (empty_parameters == null)
136                                         empty_parameters = new Parameters (null, null, Location.Null);
137                         
138                                 return empty_parameters;
139                         }
140                 }
141                 
142                 public bool Empty {
143                         get {
144                                 return (FixedParameters == null) && (ArrayParameter == null);
145                         }
146                 }
147                 
148                 public void ComputeSignature (DeclSpace ds)
149                 {
150                         signature = "";
151                         if (FixedParameters != null){
152                                 for (int i = 0; i < FixedParameters.Length; i++){
153                                         Parameter par = FixedParameters [i];
154                                         
155                                         signature += par.GetSignature (ds, loc);
156                                 }
157                         }
158                         //
159                         // Note: as per the spec, the `params' arguments (ArrayParameter)
160                         // are not used in the signature computation for a method
161                         //
162                 }
163
164                 void Error_DuplicateParameterName (string name)
165                 {
166                         Report.Error (
167                                 100, loc, "The parameter name `" + name + "' is a duplicate");
168                 }
169                 
170                 public bool VerifyArgs ()
171                 {
172                         int count;
173                         int i, j;
174
175                         if (FixedParameters == null)
176                                 return true;
177                         
178                         count = FixedParameters.Length;
179                         string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
180                         for (i = 0; i < count; i++){
181                                 string base_name = FixedParameters [i].Name;
182                                 
183                                 for (j = i + 1; j < count; j++){
184                                         if (base_name != FixedParameters [j].Name)
185                                                 continue;
186                                         Error_DuplicateParameterName (base_name);
187                                         return false;
188                                 }
189
190                                 if (base_name == array_par_name){
191                                         Error_DuplicateParameterName (base_name);
192                                         return false;
193                                 }
194                         }
195                         return true;
196                 }
197                 
198                 /// <summary>
199                 ///    Returns the signature of the Parameters evaluated in
200                 ///    the @tc environment
201                 /// </summary>
202                 public string GetSignature (DeclSpace ds)
203                 {
204                         if (signature == null){
205                                 VerifyArgs ();
206                                 ComputeSignature (ds);
207                         }
208                         
209                         return signature;
210                 }
211                 
212                 /// <summary>
213                 ///    Returns the paramenter information based on the name
214                 /// </summary>
215                 public Parameter GetParameterByName (string name, out int idx)
216                 {
217                         idx = 0;
218                         int i = 0;
219
220                         if (FixedParameters != null){
221                                 foreach (Parameter par in FixedParameters){
222                                         if (par.Name == name){
223                                                 idx = i;
224                                                 return par;
225                                         }
226                                         i++;
227                                 }
228                         }
229
230                         if (ArrayParameter != null){
231                                 if (name == ArrayParameter.Name){
232                                         idx = i;
233                                         return ArrayParameter;
234                                 }
235                         }
236                         
237                         return null;
238                 }
239
240                 bool ComputeParameterTypes (DeclSpace ds)
241                 {
242                         int extra = (ArrayParameter != null) ? 1 : 0;
243                         int i = 0;
244                         int pc;
245
246                         if (FixedParameters == null)
247                                 pc = extra;
248                         else
249                                 pc = extra + FixedParameters.Length;
250
251                         types = new Type [pc];
252                         
253                         if (!VerifyArgs ()){
254                                 FixedParameters = null;
255                                 return false;
256                         }
257
258                         bool failed = false;
259                         if (FixedParameters != null){
260                                 foreach (Parameter p in FixedParameters){
261                                         Type t = null;
262                                         
263                                         if (p.Resolve (ds, loc))
264                                                 t = p.ExternalType ();
265                                         else
266                                                 failed = true;
267
268                                         types [i] = t;
269                                         i++;
270                                 }
271                         }
272                         
273                         if (extra > 0){
274                                 if (ArrayParameter.Resolve (ds, loc))
275                                         types [i] = ArrayParameter.ExternalType ();
276                                 else 
277                                         failed = true;
278                         }
279
280                         if (failed){
281                                 types = null;
282                                 return false;
283                         }
284
285                         return true;
286                 }
287
288                 //
289                 // This variant is used by Delegates, because they need to
290                 // resolve/define names, instead of the plain LookupType
291                 //
292                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
293                 {
294                         int extra = (ArrayParameter != null) ? 1 : 0;
295                         int i = 0;
296                         int pc;
297
298                         if (FixedParameters == null)
299                                 pc = extra;
300                         else
301                                 pc = extra + FixedParameters.Length;
302                         
303                         types = new Type [pc];
304                         
305                         if (!VerifyArgs ()){
306                                 FixedParameters = null;
307                                 return false;
308                         }
309
310                         bool ok_flag = true;
311                         
312                         if (FixedParameters != null){
313                                 foreach (Parameter p in FixedParameters){
314                                         Type t = null;
315                                         
316                                         if (p.Resolve (ds, loc))
317                                                 t = p.ExternalType ();
318                                         else
319                                                 ok_flag = false;
320                                         
321                                         types [i] = t;
322                                         i++;
323                                 }
324                         }
325                         
326                         if (extra > 0){
327                                 if (ArrayParameter.Resolve (ds, loc))
328                                         types [i] = ArrayParameter.ExternalType ();
329                                 else
330                                         ok_flag = false;
331                         }
332
333                         //
334                         // invalidate the cached types
335                         //
336                         if (!ok_flag){
337                                 types = null;
338                         }
339                         
340                         return ok_flag;
341                 }
342                 
343                 /// <summary>
344                 ///   Returns the argument types as an array
345                 /// </summary>
346                 static Type [] no_types = new Type [0];
347                 
348                 public Type [] GetParameterInfo (DeclSpace ds)
349                 {
350                         if (types != null)
351                                 return types;
352                         
353                         if (FixedParameters == null && ArrayParameter == null)
354                                 return no_types;
355
356                         if (ComputeParameterTypes (ds) == false){
357                                 types = null;
358                                 return null;
359                         }
360
361                         return types;
362                 }
363
364                 /// <summary>
365                 ///   Returns the type of a given parameter, and stores in the `is_out'
366                 ///   boolean whether this is an out or ref parameter.
367                 ///
368                 ///   Note that the returned type will not contain any dereference in this
369                 ///   case (ie, you get "int" for a ref int instead of "int&"
370                 /// </summary>
371                 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
372                 {
373                         mod = Parameter.Modifier.NONE;
374                         
375                         if (!VerifyArgs ()){
376                                 FixedParameters = null;
377                                 return null;
378                         }
379
380                         if (FixedParameters == null && ArrayParameter == null)
381                                 return null;
382                         
383                         if (types == null)
384                                 if (ComputeParameterTypes (ds) == false)
385                                         return null;
386
387                         //
388                         // If this is a request for the variable lenght arg.
389                         //
390                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
391                         if (idx == array_idx)
392                                 return types [idx];
393
394                         //
395                         // Otherwise, it is a fixed parameter
396                         //
397                         Parameter p = FixedParameters [idx];
398                         mod = p.ModFlags;
399
400                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
401                                 mod |= Parameter.Modifier.ISBYREF;
402
403                         return p.ParameterType;
404                 }
405
406                 public CallingConventions GetCallingConvention ()
407                 {
408                         // For now this is the only correc thing to do
409                         return CallingConventions.Standard;
410                 }
411         }
412 }
413                 
414         
415