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