Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/argument.cs @ 16240

Last change on this file since 16240 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 15.7 KB
Line 
1//
2// argument.cs: Argument expressions
3//
4// Author:
5//   Miguel de Icaza (miguel@ximain.com)
6//   Marek Safar (marek.safar@gmail.com)
7//
8// Dual licensed under the terms of the MIT X11 or GNU GPL
9// Copyright 2003-2011 Novell, Inc.
10// Copyright 2011 Xamarin Inc
11//
12
13using System;
14using System.Collections.Generic;
15
16#if STATIC
17using IKVM.Reflection.Emit;
18#else
19using System.Reflection.Emit;
20#endif
21
22namespace Mono.CSharp
23{
24  //
25  // Argument expression used for invocation
26  //
27  public class Argument
28  {
29    public enum AType : byte
30    {
31      None = 0,
32      Ref = 1,      // ref modifier used
33      Out = 2,      // out modifier used
34      Default = 3,    // argument created from default parameter value
35      DynamicTypeName = 4,  // System.Type argument for dynamic binding
36      ExtensionType = 5,  // Instance expression inserted as the first argument
37
38      // Conditional instance expression inserted as the first argument
39      ExtensionTypeConditionalAccess = 5 | ConditionalAccessFlag,
40
41      ConditionalAccessFlag = 1 << 7
42    }
43
44    public readonly AType ArgType;
45    public Expression Expr;
46
47    public Argument (Expression expr, AType type)
48    {
49      this.Expr = expr;
50      this.ArgType = type;
51    }
52
53    public Argument (Expression expr)
54    {
55      this.Expr = expr;
56    }
57
58    #region Properties
59
60    public bool IsByRef {
61      get { return ArgType == AType.Ref || ArgType == AType.Out; }
62    }
63
64    public bool IsDefaultArgument {
65      get { return ArgType == AType.Default; }
66    }
67
68    public bool IsExtensionType {
69      get {
70        return (ArgType & AType.ExtensionType) == AType.ExtensionType;
71      }
72    }
73
74    public Parameter.Modifier Modifier {
75      get {
76        switch (ArgType) {
77        case AType.Out:
78          return Parameter.Modifier.OUT;
79
80        case AType.Ref:
81          return Parameter.Modifier.REF;
82
83        default:
84          return Parameter.Modifier.NONE;
85        }
86      }
87    }
88
89    public TypeSpec Type {
90      get { return Expr.Type; }
91    }
92
93    #endregion
94
95    public Argument Clone (Expression expr)
96    {
97      Argument a = (Argument) MemberwiseClone ();
98      a.Expr = expr;
99      return a;
100    }
101
102    public Argument Clone (CloneContext clonectx)
103    {
104      return Clone (Expr.Clone (clonectx));
105    }
106
107    public virtual Expression CreateExpressionTree (ResolveContext ec)
108    {
109      if (ArgType == AType.Default)
110        ec.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
111
112      return Expr.CreateExpressionTree (ec);
113    }
114
115
116    public virtual void Emit (EmitContext ec)
117    {
118      if (!IsByRef) {
119        if (ArgType == AType.ExtensionTypeConditionalAccess) {
120          var ie = new InstanceEmitter (Expr, false);
121          ie.Emit (ec, true);
122        } else {
123          Expr.Emit (ec);
124        }
125
126        return;
127      }
128
129      AddressOp mode = AddressOp.Store;
130      if (ArgType == AType.Ref)
131        mode |= AddressOp.Load;
132
133      IMemoryLocation ml = (IMemoryLocation) Expr;
134      ml.AddressOf (ec, mode);
135    }
136
137    public Argument EmitToField (EmitContext ec, bool cloneResult)
138    {
139      var res = Expr.EmitToField (ec);
140      if (cloneResult && res != Expr)
141        return new Argument (res, ArgType);
142
143      Expr = res;
144      return this;
145    }
146
147    public void FlowAnalysis (FlowAnalysisContext fc)
148    {
149      if (ArgType == AType.Out) {
150        var vr = Expr as VariableReference;
151        if (vr != null) {
152          if (vr.VariableInfo != null)
153            fc.SetVariableAssigned (vr.VariableInfo);
154
155          return;
156        }
157
158        var fe = Expr as FieldExpr;
159        if (fe != null) {
160          fe.SetFieldAssigned (fc);
161          return;
162        }
163
164        return;
165      }
166
167      Expr.FlowAnalysis (fc);
168    }
169
170    public string GetSignatureForError ()
171    {
172      if (Expr.eclass == ExprClass.MethodGroup)
173        return Expr.ExprClassName;
174
175      return Expr.Type.GetSignatureForError ();
176    }
177
178    public bool ResolveMethodGroup (ResolveContext ec)
179    {
180      SimpleName sn = Expr as SimpleName;
181      if (sn != null)
182        Expr = sn.GetMethodGroup ();
183
184      // FIXME: csc doesn't report any error if you try to use `ref' or
185      //        `out' in a delegate creation expression.
186      Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
187      if (Expr == null)
188        return false;
189
190      return true;
191    }
192
193    public void Resolve (ResolveContext ec)
194    {
195      // Verify that the argument is readable
196      if (ArgType != AType.Out)
197        Expr = Expr.Resolve (ec);
198
199      // Verify that the argument is writeable
200      if (Expr != null && IsByRef)
201        Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess);
202
203      if (Expr == null)
204        Expr = ErrorExpression.Instance;
205    }
206  }
207
208  public class MovableArgument : Argument
209  {
210    LocalTemporary variable;
211
212    public MovableArgument (Argument arg)
213      : this (arg.Expr, arg.ArgType)
214    {
215    }
216
217    protected MovableArgument (Expression expr, AType modifier)
218      : base (expr, modifier)
219    {
220    }
221
222    public override void Emit (EmitContext ec)
223    {
224      // TODO: Should guard against multiple emits
225      base.Emit (ec);
226
227      // Release temporary variable when used
228      if (variable != null)
229        variable.Release (ec);
230    }
231
232    public void EmitToVariable (EmitContext ec)
233    {
234      var type = Expr.Type;
235      if (IsByRef) {
236        var ml = (IMemoryLocation) Expr;
237        ml.AddressOf (ec, AddressOp.LoadStore);
238        type = ReferenceContainer.MakeType (ec.Module, type);
239      } else {
240        Expr.Emit (ec);
241      }
242
243      variable = new LocalTemporary (type);
244      variable.Store (ec);
245
246      Expr = variable;
247    }
248  }
249
250  public class NamedArgument : MovableArgument
251  {
252    public readonly string Name;
253    readonly Location loc;
254
255    public NamedArgument (string name, Location loc, Expression expr)
256      : this (name, loc, expr, AType.None)
257    {
258    }
259
260    public NamedArgument (string name, Location loc, Expression expr, AType modifier)
261      : base (expr, modifier)
262    {
263      this.Name = name;
264      this.loc = loc;
265    }
266
267    public override Expression CreateExpressionTree (ResolveContext ec)
268    {
269      ec.Report.Error (853, loc, "An expression tree cannot contain named argument");
270      return base.CreateExpressionTree (ec);
271    }
272
273    public Location Location {
274      get { return loc; }
275    }
276  }
277 
278  public class Arguments
279  {
280    sealed class ArgumentsOrdered : Arguments
281    {
282      readonly List<MovableArgument> ordered;
283
284      public ArgumentsOrdered (Arguments args)
285        : base (args.Count)
286      {
287        AddRange (args);
288        ordered = new List<MovableArgument> ();
289      }
290
291      public void AddOrdered (MovableArgument arg)
292      {
293        ordered.Add (arg);
294      }
295
296      public override void FlowAnalysis (FlowAnalysisContext fc, List<MovableArgument> movable = null)
297      {
298        foreach (var arg in ordered) {
299          if (arg.ArgType != Argument.AType.Out)
300            arg.FlowAnalysis (fc);
301        }
302
303        base.FlowAnalysis (fc, ordered);
304      }
305
306      public override Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
307      {
308        foreach (var a in ordered) {
309          if (prepareAwait)
310            a.EmitToField (ec, false);
311          else
312            a.EmitToVariable (ec);
313        }
314
315        return base.Emit (ec, dup_args, prepareAwait);
316      }
317    }
318
319    // Try not to add any more instances to this class, it's allocated a lot
320    List<Argument> args;
321
322    public Arguments (int capacity)
323    {
324      args = new List<Argument> (capacity);
325    }
326
327    private Arguments (List<Argument> args)
328    {
329      this.args = args;
330    }
331
332    public void Add (Argument arg)
333    {
334      args.Add (arg);
335    }
336
337    public void AddRange (Arguments args)
338    {
339      this.args.AddRange (args.args);
340    }
341
342    public bool ContainsEmitWithAwait ()
343    {
344      foreach (var arg in args) {
345        if (arg.Expr.ContainsEmitWithAwait ())
346          return true;
347      }
348
349      return false;
350    }
351
352    public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
353    {
354      Location loc = Location.Null;
355      var all = new ArrayInitializer (args.Count, loc);
356
357      MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
358
359      foreach (Argument a in args) {
360        Arguments dargs = new Arguments (2);
361
362        // CSharpArgumentInfoFlags.None = 0
363        const string info_flags_enum = "CSharpArgumentInfoFlags";
364        Expression info_flags = new IntLiteral (rc.BuiltinTypes, 0, loc);
365
366        if (a.Expr is Constant) {
367          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
368            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "Constant", loc));
369        } else if (a.ArgType == Argument.AType.Ref) {
370          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
371            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsRef", loc));
372          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
373            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
374        } else if (a.ArgType == Argument.AType.Out) {
375          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
376            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsOut", loc));
377          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
378            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
379        } else if (a.ArgType == Argument.AType.DynamicTypeName) {
380          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
381            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsStaticType", loc));
382        }
383
384        var arg_type = a.Expr.Type;
385
386        if (arg_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && arg_type != InternalType.NullLiteral) {
387          MethodGroupExpr mg = a.Expr as MethodGroupExpr;
388          if (mg != null) {
389            rc.Report.Error (1976, a.Expr.Location,
390              "The method group `{0}' cannot be used as an argument of dynamic operation. Consider using parentheses to invoke the method",
391              mg.Name);
392          } else if (arg_type == InternalType.AnonymousMethod) {
393            rc.Report.Error (1977, a.Expr.Location,
394              "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast");
395          } else if (arg_type.Kind == MemberKind.Void || arg_type == InternalType.Arglist || arg_type.IsPointer) {
396            rc.Report.Error (1978, a.Expr.Location,
397              "An expression of type `{0}' cannot be used as an argument of dynamic operation",
398              arg_type.GetSignatureForError ());
399          }
400
401          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
402            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
403        }
404
405        string named_value;
406        NamedArgument na = a as NamedArgument;
407        if (na != null) {
408          info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
409            new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "NamedArgument", loc));
410
411          named_value = na.Name;
412        } else {
413          named_value = null;
414        }
415
416        dargs.Add (new Argument (info_flags));
417        dargs.Add (new Argument (new StringLiteral (rc.BuiltinTypes, named_value, loc)));
418        all.Add (new Invocation (new MemberAccess (new MemberAccess (binder, "CSharpArgumentInfo", loc), "Create", loc), dargs));
419      }
420
421      return all;
422    }
423
424    public static Arguments CreateForExpressionTree (ResolveContext ec, Arguments args, params Expression[] e)
425    {
426      Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
427      for (int i = 0; i < e.Length; ++i) {
428        if (e [i] != null)
429          all.Add (new Argument (e[i]));
430      }
431
432      if (args != null) {
433        foreach (Argument a in args.args) {
434          Expression tree_arg = a.CreateExpressionTree (ec);
435          if (tree_arg != null)
436            all.Add (new Argument (tree_arg));
437        }
438      }
439
440      return all;
441    }
442
443    public void CheckArrayAsAttribute (CompilerContext ctx)
444    {
445      foreach (Argument arg in args) {
446        // Type is undefined (was error 246)
447        if (arg.Type == null)
448          continue;
449
450        if (arg.Type.IsArray)
451          ctx.Report.Warning (3016, 1, arg.Expr.Location, "Arrays as attribute arguments are not CLS-compliant");
452      }
453    }
454
455    public Arguments Clone (CloneContext ctx)
456    {
457      Arguments cloned = new Arguments (args.Count);
458      foreach (Argument a in args)
459        cloned.Add (a.Clone (ctx));
460
461      return cloned;
462    }
463
464    public int Count {
465      get { return args.Count; }
466    }
467
468    //
469    // Emits a list of resolved Arguments
470    //
471    public void Emit (EmitContext ec)
472    {
473      Emit (ec, false, false);
474    }
475
476    //
477    // if `dup_args' is true or any of arguments contains await.
478    // A copy of all arguments will be returned to the caller
479    //
480    public virtual Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
481    {
482      List<Argument> dups;
483
484      if ((dup_args && Count != 0) || prepareAwait)
485        dups = new List<Argument> (Count);
486      else
487        dups = null;
488
489      LocalTemporary lt;
490      foreach (Argument a in args) {
491        if (prepareAwait) {
492          dups.Add (a.EmitToField (ec, true));
493          continue;
494        }
495       
496        a.Emit (ec);
497
498        if (!dup_args) {
499          continue;
500        }
501
502        if (a.Expr.IsSideEffectFree) {
503          //
504          // No need to create a temporary variable for side effect free expressions. I assume
505          // all side-effect free expressions are cheap, this has to be tweaked when we become
506          // more aggressive on detection
507          //
508          dups.Add (a);
509        } else {
510          ec.Emit (OpCodes.Dup);
511
512          // TODO: Release local temporary on next Emit
513          // Need to add a flag to argument to indicate this
514          lt = new LocalTemporary (a.Type);
515          lt.Store (ec);
516
517          dups.Add (new Argument (lt, a.ArgType));
518        }
519      }
520
521      if (dups != null)
522        return new Arguments (dups);
523
524      return null;
525    }
526
527    public virtual void FlowAnalysis (FlowAnalysisContext fc, List<MovableArgument> movable = null)
528    {
529      bool has_out = false;
530      foreach (var arg in args) {
531        if (arg.ArgType == Argument.AType.Out) {
532          has_out = true;
533          continue;
534        }
535
536        if (movable == null) {
537          arg.FlowAnalysis (fc);
538          continue;
539        }
540
541        var ma = arg as MovableArgument;
542        if (ma != null && !movable.Contains (ma))
543          arg.FlowAnalysis (fc);
544      }
545
546      if (!has_out)
547        return;
548
549      foreach (var arg in args) {
550        if (arg.ArgType != Argument.AType.Out)
551          continue;
552
553        arg.FlowAnalysis (fc);
554      }
555    }
556
557    public List<Argument>.Enumerator GetEnumerator ()
558    {
559      return args.GetEnumerator ();
560    }
561
562    //
563    // At least one argument is of dynamic type
564    //
565    public bool HasDynamic {
566      get {
567        foreach (Argument a in args) {
568          if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef)
569            return true;
570        }
571       
572        return false;
573      }
574    }
575
576    //
577    // At least one argument is named argument
578    //
579    public bool HasNamed {
580      get {
581        foreach (Argument a in args) {
582          if (a is NamedArgument)
583            return true;
584        }
585       
586        return false;
587      }
588    }
589
590
591    public void Insert (int index, Argument arg)
592    {
593      args.Insert (index, arg);
594    }
595
596    public static System.Linq.Expressions.Expression[] MakeExpression (Arguments args, BuilderContext ctx)
597    {
598      if (args == null || args.Count == 0)
599        return null;
600
601      var exprs = new System.Linq.Expressions.Expression [args.Count];
602      for (int i = 0; i < exprs.Length; ++i) {
603        Argument a = args.args [i];
604        exprs[i] = a.Expr.MakeExpression (ctx);
605      }
606
607      return exprs;
608    }
609
610    //
611    // For named arguments when the order of execution is different
612    // to order of invocation
613    //
614    public Arguments MarkOrderedArgument (NamedArgument a)
615    {
616      //
617      // An expression has no effect on left-to-right execution
618      //
619      if (a.Expr.IsSideEffectFree)
620        return this;
621
622      ArgumentsOrdered ra = this as ArgumentsOrdered;
623      if (ra == null) {
624        ra = new ArgumentsOrdered (this);
625
626        for (int i = 0; i < args.Count; ++i) {
627          var la = args [i];
628          if (la == a)
629            break;
630
631          //
632          // When the argument is filled later by default expression
633          //
634          if (la == null)
635            continue;
636
637          var ma = la as MovableArgument;
638          if (ma == null) {
639            ma = new MovableArgument (la);
640            ra.args[i] = ma;
641          }
642
643          ra.AddOrdered (ma);
644        }
645      }
646
647      ra.AddOrdered (a);
648      return ra;
649    }
650
651    //
652    // Returns dynamic when at least one argument is of dynamic type
653    //
654    public void Resolve (ResolveContext ec, out bool dynamic)
655    {
656      dynamic = false;
657      foreach (Argument a in args) {
658        a.Resolve (ec);
659        if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef)
660          dynamic = true;
661      }
662    }
663
664    public void RemoveAt (int index)
665    {
666      args.RemoveAt (index);
667    }
668
669    public Argument this [int index] {
670      get { return args [index]; }
671      set { args [index] = value; }
672    }
673  }
674}
Note: See TracBrowser for help on using the repository browser.