Add new test
[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 string   TypeName;
33                 public readonly string   Name;
34                 public readonly Modifier ModFlags;
35                 public Attributes OptAttributes;
36                 public Type ParameterType;
37                 
38                 public Parameter (string type, string name, Modifier mod, Attributes attrs)
39                 {
40                         Name = name;
41                         ModFlags = mod;
42                         TypeName = type;
43                         OptAttributes = attrs;
44                 }
45
46                 public bool Resolve (DeclSpace ds, Location l)
47                 {
48                         ParameterType = RootContext.LookupType (ds, TypeName, false, l);
49                         return ParameterType != null;
50                 }
51
52                 public Type ExternalType ()
53                 {
54                         if ((ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
55                                 string n = ParameterType.FullName + "&";
56                                 Type t;
57                                 
58                                 t = Type.GetType (n);
59
60                                 //
61                                 // It is a type defined by the source code we are compiling
62                                 //
63                                 if (t == null){
64                                         ModuleBuilder mb = RootContext.ModuleBuilder;
65
66                                         t = mb.GetType (n);
67                                 }
68
69                                 return t;
70                         }
71
72                         return ParameterType;
73                 }
74                 
75                 public ParameterAttributes Attributes {
76                         get {
77                                 switch (ModFlags){
78                                 case Modifier.NONE:
79                                         return ParameterAttributes.None;
80                                 case Modifier.REF:
81                                         return ParameterAttributes.None;
82                                 case Modifier.OUT:
83                                         return ParameterAttributes.Out;
84                                 case Modifier.PARAMS:
85                                         return 0;
86                                 }
87                                 
88                                 return ParameterAttributes.None;
89                         }
90                 }
91                 
92                 /// <summary>
93                 ///   Returns the signature for this parameter evaluating it on the
94                 ///   @tc context
95                 /// </summary>
96                 public string GetSignature (DeclSpace ds, Location loc)
97                 {
98                         if (ParameterType == null){
99                                 if (!Resolve (ds, loc))
100                                         return null;
101                         }
102
103                         return ExternalType ().FullName;
104                 }
105         }
106
107         /// <summary>
108         ///   Represents the methods parameters
109         /// </summary>
110         public class Parameters {
111                 public Parameter [] FixedParameters;
112                 public readonly Parameter ArrayParameter;
113                 string signature;
114                 Type [] types;
115                 Location loc;
116                 
117                 static Parameters empty_parameters;
118                 
119                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
120                 {
121                         FixedParameters = fixed_parameters;
122                         ArrayParameter  = array_parameter;
123                         loc = l;
124                 }
125
126                 /// <summary>
127                 ///   This is used to reuse a set of empty parameters, because they
128                 ///   are common
129                 /// </summary>
130                 public static Parameters GetEmptyReadOnlyParameters ()
131                 {
132                         if (empty_parameters == null)
133                                 empty_parameters = new Parameters (null, null, Location.Null);
134                         
135                         return empty_parameters;
136                 }
137                 
138                 public bool Empty {
139                         get {
140                                 return (FixedParameters == null) && (ArrayParameter == null);
141                         }
142                 }
143                 
144                 public void ComputeSignature (DeclSpace ds)
145                 {
146                         signature = "";
147                         if (FixedParameters != null){
148                                 for (int i = 0; i < FixedParameters.Length; i++){
149                                         Parameter par = FixedParameters [i];
150                                         
151                                         signature += par.GetSignature (ds, loc);
152                                 }
153                         }
154                         //
155                         // Note: as per the spec, the `params' arguments (ArrayParameter)
156                         // are not used in the signature computation for a method
157                         //
158                 }
159
160                 static void error100 (string name)
161                 {
162                         Report.Error (
163                                 100, "The parameter name `" + name + "' is a duplicate");
164                 }
165                 
166                 public bool VerifyArgs ()
167                 {
168                         int count;
169                         int i, j;
170
171                         if (FixedParameters == null)
172                                 return true;
173                         
174                         count = FixedParameters.Length;
175                         for (i = 0; i < count; i++){
176                                 string base_name = FixedParameters [i].Name;
177                                 
178                                 for (j = i + 1; j < count; j++){
179                                         if (base_name != FixedParameters [j].Name)
180                                                 continue;
181                                         error100 (base_name);
182                                         return false;
183                                 }
184
185                                 if (base_name == ArrayParameter.Name){
186                                         error100 (base_name);
187                                         return false;
188                                 }
189                         }
190                         return true;
191                 }
192                 
193                 /// <summary>
194                 ///    Returns the signature of the Parameters evaluated in
195                 ///    the @tc environment
196                 /// </summary>
197                 public string GetSignature (DeclSpace ds)
198                 {
199                         if (signature == null){
200                                 VerifyArgs ();
201                                 ComputeSignature (ds);
202                         }
203                         
204                         return signature;
205                 }
206                 
207                 /// <summary>
208                 ///    Returns the paramenter information based on the name
209                 /// </summary>
210                 public Parameter GetParameterByName (string name, out int idx)
211                 {
212                         idx = 0;
213                         int i = 0;
214
215                         if (FixedParameters != null){
216                                 foreach (Parameter par in FixedParameters){
217                                         if (par.Name == name){
218                                                 idx = i;
219                                                 return par;
220                                         }
221                                         i++;
222                                 }
223                         }
224
225                         if (ArrayParameter != null){
226                                 if (name == ArrayParameter.Name){
227                                         idx = i;
228                                         return ArrayParameter;
229                                 }
230                         }
231                         
232                         return null;
233                 }
234
235                 bool ComputeParameterTypes (DeclSpace ds)
236                 {
237                         int extra = (ArrayParameter != null) ? 1 : 0;
238                         int i = 0;
239                         int pc;
240
241                         if (FixedParameters == null)
242                                 pc = extra;
243                         else
244                                 pc = extra + FixedParameters.Length;
245                         
246                         types = new Type [pc];
247                         
248                         if (!VerifyArgs ()){
249                                 FixedParameters = null;
250                                 return false;
251                         }
252
253                         if (FixedParameters != null){
254                                 foreach (Parameter p in FixedParameters){
255                                         Type t = null;
256                                         
257                                         if (p.Resolve (ds, loc))
258                                                 t = p.ExternalType ();
259                                         
260                                         types [i] = t;
261                                         i++;
262                                 }
263                         }
264                         
265                         if (extra > 0){
266                                 if (ArrayParameter.Resolve (ds, loc))
267                                         types [i] = ArrayParameter.ExternalType ();
268                         }
269
270                         return true;
271                 }
272                 
273                 /// <summary>
274                 ///   Returns the argument types as an array
275                 /// </summary>
276                 static Type [] no_types = new Type [0];
277                 
278                 public Type [] GetParameterInfo (DeclSpace ds)
279                 {
280                         if (types != null)
281                                 return types;
282                         
283                         if (FixedParameters == null && ArrayParameter == null)
284                                 return no_types;
285
286                         if (ComputeParameterTypes (ds) == false)
287                                 return null;
288                         
289                         return types;
290                 }
291
292                 /// <summary>
293                 ///   Returns the type of a given parameter, and stores in the `is_out'
294                 ///   boolean whether this is an out or ref parameter.
295                 ///
296                 ///   Note that the returned type will not contain any dereference in this
297                 ///   case (ie, you get "int" for a ref int instead of "int&"
298                 /// </summary>
299                 public Type GetParameterInfo (DeclSpace ds, int idx, out bool is_out)
300                 {
301                         is_out = false;
302                         
303                         if (!VerifyArgs ()){
304                                 FixedParameters = null;
305                                 return null;
306                         }
307
308                         if (FixedParameters == null && ArrayParameter == null)
309                                 return null;
310                         
311                         if (types == null)
312                                 if (ComputeParameterTypes (ds) == false){
313                                         is_out = false;
314                                         return null;
315                                 }
316
317                         //
318                         // If this is a request for the variable lenght arg.
319                         //
320                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
321                         if (idx == array_idx){
322                                 is_out = false;
323                                 return types [idx];
324                         } 
325
326                         //
327                         // Otherwise, it is a fixed parameter
328                         //
329                         Parameter p = FixedParameters [idx];
330                         is_out = ((p.ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0);
331
332                         return p.ParameterType;
333                 }
334
335                 public CallingConventions GetCallingConvention ()
336                 {
337                         // For now this is the only correc thing to do
338                         return CallingConventions.Standard;
339                 }
340         }
341 }
342                 
343         
344