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