2 // argument.cs: Argument expressions
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003-2008 Novell, Inc.
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
20 // Argument expression used for invocation
24 public enum AType : byte
26 Ref = 1, // ref modifier used
27 Out = 2, // out modifier used
28 Default = 3 // argument created from default parameter value
31 public readonly AType ArgType;
32 public Expression Expr;
34 public Argument (Expression expr, AType type)
40 public Argument (Expression expr)
43 throw new ArgumentNullException ();
49 get { return Expr.Type; }
52 public Parameter.Modifier Modifier {
56 return Parameter.Modifier.OUT;
59 return Parameter.Modifier.REF;
62 return Parameter.Modifier.NONE;
67 public virtual Expression CreateExpressionTree (EmitContext ec)
69 if (ArgType == AType.Default)
70 Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
72 return Expr.CreateExpressionTree (ec);
75 public string GetSignatureForError ()
77 if (Expr.eclass == ExprClass.MethodGroup)
78 return Expr.ExprClassName;
80 return TypeManager.CSharpName (Expr.Type);
84 get { return ArgType == AType.Ref || ArgType == AType.Out; }
87 public bool IsDefaultArgument {
88 get { return ArgType == AType.Default; }
91 public bool ResolveMethodGroup (EmitContext ec)
93 SimpleName sn = Expr as SimpleName;
95 Expr = sn.GetMethodGroup ();
97 // FIXME: csc doesn't report any error if you try to use `ref' or
98 // `out' in a delegate creation expression.
99 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
106 public void Resolve (EmitContext ec)
108 if (Expr == EmptyExpression.Null)
111 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
112 // Verify that the argument is readable
113 if (ArgType != AType.Out)
114 Expr = Expr.Resolve (ec);
116 // Verify that the argument is writeable
117 if (Expr != null && IsByRef)
118 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess);
121 Expr = EmptyExpression.Null;
125 public virtual void Emit (EmitContext ec)
132 AddressOp mode = AddressOp.Store;
133 if (ArgType == AType.Ref)
134 mode |= AddressOp.Load;
136 IMemoryLocation ml = (IMemoryLocation) Expr;
137 ParameterReference pr = ml as ParameterReference;
140 // ParameterReferences might already be references, so we want
141 // to pass just the value
143 if (pr != null && pr.IsRef)
146 ml.AddressOf (ec, mode);
149 public Argument Clone (CloneContext clonectx)
151 Argument a = (Argument) MemberwiseClone ();
152 a.Expr = Expr.Clone (clonectx);
157 public class NamedArgument : Argument
159 public readonly LocatedToken Name;
160 LocalTemporary variable;
162 public NamedArgument (LocatedToken name, Expression expr)
168 public override Expression CreateExpressionTree (EmitContext ec)
170 Report.Error (853, Name.Location, "An expression tree cannot contain named argument");
171 return base.CreateExpressionTree (ec);
174 public override void Emit (EmitContext ec)
176 // TODO: Should guard against multiple emits
179 // Release temporary variable when used
180 if (variable != null)
181 variable.Release (ec);
184 public void EmitAssign (EmitContext ec)
187 variable = new LocalTemporary (Expr.Type);
194 public class Arguments
196 ArrayList args; // TODO: This should really be linked list
197 ArrayList reordered; // TODO: LinkedList
199 public Arguments (int capacity)
201 args = new ArrayList (capacity);
204 public int Add (Argument arg)
206 return args.Add (arg);
209 public void AddRange (Arguments args)
211 this.args.AddRange (args.args);
214 public static Arguments CreateForExpressionTree (EmitContext ec, Arguments args, params Expression[] e)
216 Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
217 for (int i = 0; i < e.Length; ++i) {
219 all.Add (new Argument (e[i]));
223 foreach (Argument a in args.args) {
224 Expression tree_arg = a.CreateExpressionTree (ec);
225 if (tree_arg != null)
226 all.Add (new Argument (tree_arg));
233 public void CheckArrayAsAttribute ()
235 foreach (Argument arg in args) {
236 // Type is undefined (was error 246)
237 if (arg.Type == null)
240 if (arg.Type.IsArray)
241 Report.Warning (3016, 1, arg.Expr.Location, "Arrays as attribute arguments are not CLS-compliant");
245 public Arguments Clone (CloneContext ctx)
247 Arguments cloned = new Arguments (args.Count);
248 foreach (Argument a in args)
249 cloned.Add (a.Clone (ctx));
255 get { return args.Count; }
259 // Emits a list of resolved Arguments
261 public void Emit (EmitContext ec)
263 Emit (ec, false, null);
267 // if `dup_args' is true, a copy of the arguments will be left
268 // on the stack. If `dup_args' is true, you can specify `this_arg'
269 // which will be duplicated before any other args. Only EmitCall
270 // should be using this interface.
272 public void Emit (EmitContext ec, bool dup_args, LocalTemporary this_arg)
274 LocalTemporary[] temps = null;
276 if (dup_args && Count != 0)
277 temps = new LocalTemporary [Count];
279 if (reordered != null && Count > 1) {
280 foreach (NamedArgument na in reordered)
285 foreach (Argument a in args) {
288 ec.ig.Emit (OpCodes.Dup);
289 (temps [i++] = new LocalTemporary (a.Type)).Store (ec);
294 if (this_arg != null)
297 for (i = 0; i < temps.Length; i++) {
299 temps[i].Release (ec);
304 public bool GetAttributableValue (EmitContext ec, out object[] values)
306 values = new object [args.Count];
307 for (int j = 0; j < values.Length; ++j) {
308 Argument a = this [j];
309 if (!a.Expr.GetAttributableValue (ec, a.Type, out values[j]))
316 public IEnumerator GetEnumerator ()
318 return args.GetEnumerator ();
321 public void Insert (int index, Argument arg)
323 args.Insert (index, arg);
326 public void MarkReorderedArgument (NamedArgument a)
329 // Constant expression can have no effect on left-to-right execution
331 if (a.Expr is Constant)
334 if (reordered == null)
335 reordered = new ArrayList ();
340 public void Resolve (EmitContext ec)
342 foreach (Argument a in args)
346 public void MutateHoistedGenericType (AnonymousMethodStorey storey)
348 foreach (Argument a in args)
349 a.Expr.MutateHoistedGenericType (storey);
352 public void RemoveAt (int index)
354 args.RemoveAt (index);
357 public Argument this [int index] {
358 get { return (Argument) args [index]; }
359 set { args [index] = value; }