~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/argument.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

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