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