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/parameter.cs @ 15682

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

#2077: created branch and added first version

File size: 39.6 KB
Line 
1//
2// parameter.cs: Parameter definition.
3//
4// Author: Miguel de Icaza (miguel@gnu.org)
5//         Marek Safar (marek.safar@seznam.cz)
6//
7// Dual licensed under the terms of the MIT X11 or GNU GPL
8//
9// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10// Copyright 2003-2008 Novell, Inc.
11// Copyright 2011 Xamarin Inc
12//
13//
14using System;
15using System.Text;
16
17#if STATIC
18using MetaType = IKVM.Reflection.Type;
19using IKVM.Reflection;
20using IKVM.Reflection.Emit;
21#else
22using MetaType = System.Type;
23using System.Reflection;
24using System.Reflection.Emit;
25#endif
26
27namespace Mono.CSharp {
28
29  /// <summary>
30  ///   Abstract Base class for parameters of a method.
31  /// </summary>
32  public abstract class ParameterBase : Attributable
33  {
34    protected ParameterBuilder builder;
35
36    public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
37    {
38#if false
39      if (a.Type == pa.MarshalAs) {
40        UnmanagedMarshal marshal = a.GetMarshal (this);
41        if (marshal != null) {
42          builder.SetMarshal (marshal);
43        }
44        return;
45      }
46#endif
47      if (a.HasSecurityAttribute) {
48        a.Error_InvalidSecurityParent ();
49        return;
50      }
51
52      if (a.Type == pa.Dynamic) {
53        a.Error_MisusedDynamicAttribute ();
54        return;
55      }
56
57      builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
58    }
59
60    public ParameterBuilder Builder {
61      get {
62        return builder;
63      }
64    }
65
66    public override bool IsClsComplianceRequired()
67    {
68      return false;
69    }
70  }
71
72  /// <summary>
73  /// Class for applying custom attributes on the return type
74  /// </summary>
75  public class ReturnParameter : ParameterBase
76  {
77    MemberCore method;
78
79    // TODO: merge method and mb
80    public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
81    {
82      this.method = method;
83      try {
84        builder = mb.DefineParameter (0, ParameterAttributes.None, "");     
85      }
86      catch (ArgumentOutOfRangeException) {
87        method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
88      }
89    }
90
91    public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
92    {
93      if (a.Type == pa.CLSCompliant) {
94        method.Compiler.Report.Warning (3023, 1, a.Location,
95          "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
96      }
97
98      // This occurs after Warning -28
99      if (builder == null)
100        return;
101
102      base.ApplyAttributeBuilder (a, ctor, cdata, pa);
103    }
104
105    public override AttributeTargets AttributeTargets {
106      get {
107        return AttributeTargets.ReturnValue;
108      }
109    }
110
111    /// <summary>
112    /// Is never called
113    /// </summary>
114    public override string[] ValidAttributeTargets {
115      get {
116        return null;
117      }
118    }
119  }
120
121  public class ImplicitLambdaParameter : Parameter
122  {
123    public ImplicitLambdaParameter (string name, Location loc)
124      : base (null, name, Modifier.NONE, null, loc)
125    {
126    }
127
128    public override TypeSpec Resolve (IMemberContext ec, int index)
129    {
130      if (parameter_type == null)
131        throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
132          Name);
133
134      base.idx = index;
135      return parameter_type;
136    }
137
138    public void SetParameterType (TypeSpec type)
139    {
140      parameter_type = type;
141    }
142  }
143
144  public class ParamsParameter : Parameter {
145    public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
146      base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
147    {
148    }
149
150    public override TypeSpec Resolve (IMemberContext ec, int index)
151    {
152      if (base.Resolve (ec, index) == null)
153        return null;
154
155      var ac = parameter_type as ArrayContainer;
156      if (ac == null || ac.Rank != 1) {
157        ec.Module.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
158        return null;
159      }
160
161      return parameter_type;
162    }
163
164    public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
165    {
166      base.ApplyAttributes (mb, cb, index, pa);
167      pa.ParamArray.EmitAttribute (builder);
168    }
169  }
170
171  public class ArglistParameter : Parameter {
172    // Doesn't have proper type because it's never chosen for better conversion
173    public ArglistParameter (Location loc) :
174      base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
175    {
176      parameter_type = InternalType.Arglist;
177    }
178
179    public override void  ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
180    {
181      // Nothing to do
182    }
183
184    public override bool CheckAccessibility (InterfaceMemberBase member)
185    {
186      return true;
187    }
188
189    public override TypeSpec Resolve (IMemberContext ec, int index)
190    {
191      return parameter_type;
192    }
193  }
194
195  public interface IParameterData
196  {
197    Expression DefaultValue { get; }
198    bool HasExtensionMethodModifier { get; }
199    bool HasDefaultValue { get; }
200    Parameter.Modifier ModFlags { get; }
201    string Name { get; }
202  }
203
204  //
205  // Parameter information created by parser
206  //
207  public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
208  {
209    [Flags]
210    public enum Modifier : byte {
211      NONE    = 0,
212      PARAMS  = 1 << 0,
213      REF = 1 << 1,
214      OUT = 1 << 2,
215      This = 1 << 3,
216      CallerMemberName = 1 << 4,
217      CallerLineNumber = 1 << 5,
218      CallerFilePath = 1 << 6,
219
220      RefOutMask = REF | OUT,
221      ModifierMask = PARAMS | REF | OUT | This,
222      CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath
223    }
224
225    static readonly string[] attribute_targets = new [] { "param" };
226
227    FullNamedExpression texpr;
228    Modifier modFlags;
229    string name;
230    Expression default_expr;
231    protected TypeSpec parameter_type;
232    readonly Location loc;
233    protected int idx;
234    public bool HasAddressTaken;
235
236    TemporaryVariableReference expr_tree_variable;
237
238    HoistedParameter hoisted_variant;
239
240    public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
241    {
242      this.name = name;
243      modFlags = mod;
244      this.loc = loc;
245      texpr = type;
246
247      // Only assign, attributes will be attached during resolve
248      base.attributes = attrs;
249    }
250
251    #region Properties
252
253    public Expression DefaultExpression {
254      get {
255        return default_expr;
256      }
257    }
258
259    public DefaultParameterValueExpression DefaultValue {
260      get {
261        return default_expr as DefaultParameterValueExpression;
262      }
263      set {
264        default_expr = value;
265      }
266    }
267
268    Expression IParameterData.DefaultValue {
269      get {
270        var expr = default_expr as DefaultParameterValueExpression;
271        return expr == null ? default_expr : expr.Child;
272      }
273    }
274
275    bool HasOptionalExpression {
276      get {
277        return default_expr is DefaultParameterValueExpression;
278      }
279    }
280
281    public Location Location {
282      get {
283        return loc;
284      }
285    }
286
287    public Modifier ParameterModifier {
288      get {
289        return modFlags;
290      }
291    }
292
293    public TypeSpec Type {
294      get {
295        return parameter_type;
296      }
297      set {
298        parameter_type = value;
299      }
300    }
301
302    public FullNamedExpression TypeExpression  {
303      get {
304        return texpr;
305      }
306    }
307
308    public override string[] ValidAttributeTargets {
309      get {
310        return attribute_targets;
311      }
312    }
313
314    #endregion
315
316    public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
317    {
318      if (a.Type == pa.In && ModFlags == Modifier.OUT) {
319        a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
320        return;
321      }
322
323      if (a.Type == pa.ParamArray) {
324        a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
325        return;
326      }
327
328      if (a.Type == pa.Out && (ModFlags & Modifier.REF) != 0 &&
329          !OptAttributes.Contains (pa.In)) {
330        a.Report.Error (662, a.Location,
331          "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
332        return;
333      }
334
335      if (a.Type == pa.CLSCompliant) {
336        a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
337      } else if (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter) {
338        if (HasOptionalExpression) {
339          a.Report.Error (1745, a.Location,
340            "Cannot specify `{0}' attribute on optional parameter `{1}'",
341            a.Type.GetSignatureForError ().Replace ("Attribute", ""), Name);
342        }
343
344        if (a.Type == pa.DefaultParameterValue)
345          return;
346      } else if (a.Type == pa.CallerMemberNameAttribute) {
347        if ((modFlags & Modifier.CallerMemberName) == 0) {
348          a.Report.Error (4022, a.Location,
349            "The CallerMemberName attribute can only be applied to parameters with default value");
350        }
351      } else if (a.Type == pa.CallerLineNumberAttribute) {
352        if ((modFlags & Modifier.CallerLineNumber) == 0) {
353          a.Report.Error (4020, a.Location,
354            "The CallerLineNumber attribute can only be applied to parameters with default value");
355        }
356      } else if (a.Type == pa.CallerFilePathAttribute) {
357        if ((modFlags & Modifier.CallerFilePath) == 0) {
358          a.Report.Error (4021, a.Location,
359            "The CallerFilePath attribute can only be applied to parameters with default value");
360        }
361      }
362
363      base.ApplyAttributeBuilder (a, ctor, cdata, pa);
364    }
365   
366    public virtual bool CheckAccessibility (InterfaceMemberBase member)
367    {
368      if (parameter_type == null)
369        return true;
370
371      return member.IsAccessibleAs (parameter_type);
372    }
373
374    bool IsValidCallerContext (MemberCore memberContext)
375    {
376      var m = memberContext as Method;
377      if (m != null)
378        return !m.IsPartialImplementation;
379
380      return true;
381    }
382
383    // <summary>
384    //   Resolve is used in method definitions
385    // </summary>
386    public virtual TypeSpec Resolve (IMemberContext rc, int index)
387    {
388      if (parameter_type != null)
389        return parameter_type;
390
391      if (attributes != null)
392        attributes.AttachTo (this, rc);
393
394      parameter_type = texpr.ResolveAsType (rc);
395      if (parameter_type == null)
396        return null;
397
398      this.idx = index;
399
400      if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
401        rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
402          GetSignatureForError ());
403        return null;
404      }
405
406      VarianceDecl.CheckTypeVariance (parameter_type,
407        (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
408        rc);
409
410      if (parameter_type.IsStatic) {
411        rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
412          texpr.GetSignatureForError ());
413        return parameter_type;
414      }
415
416      if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
417        rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
418          parameter_type.GetSignatureForError ());
419      }
420
421      return parameter_type;
422    }
423
424    void ResolveCallerAttributes (ResolveContext rc)
425    {
426      var pa = rc.Module.PredefinedAttributes;
427      TypeSpec caller_type;
428      Attribute callerMemberName = null, callerFilePath = null;
429
430      foreach (var attr in attributes.Attrs) {
431        var atype = attr.ResolveTypeForComparison ();
432        if (atype == null)
433          continue;
434
435        if (atype == pa.CallerMemberNameAttribute) {
436          caller_type = rc.BuiltinTypes.String;
437          if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
438            rc.Report.Error (4019, attr.Location,
439              "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
440              caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
441          }
442
443          if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
444            rc.Report.Warning (4026, 1, attr.Location,
445              "The CallerMemberName applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
446              name);
447          }
448
449          modFlags |= Modifier.CallerMemberName;
450          callerMemberName = attr;
451          continue;
452        }
453
454        if (atype == pa.CallerLineNumberAttribute) {
455          caller_type = rc.BuiltinTypes.Int;
456          if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
457            rc.Report.Error (4017, attr.Location,
458              "The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
459              caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
460          }
461
462          if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
463            rc.Report.Warning (4024, 1, attr.Location,
464              "The CallerLineNumberAttribute applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
465              name);
466          }
467
468          modFlags |= Modifier.CallerLineNumber;
469          continue;
470        }
471
472        if (atype == pa.CallerFilePathAttribute) {
473          caller_type = rc.BuiltinTypes.String;
474          if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
475            rc.Report.Error (4018, attr.Location,
476              "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
477              caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
478          }
479
480          if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
481            rc.Report.Warning (4025, 1, attr.Location,
482              "The CallerFilePath applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
483              name);
484          }
485
486          modFlags |= Modifier.CallerFilePath;
487          callerFilePath = attr;
488          continue;
489        }
490      }
491
492      if ((modFlags & Modifier.CallerLineNumber) != 0) {
493        if (callerMemberName != null) {
494          rc.Report.Warning (7081, 1, callerMemberName.Location,
495            "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
496            Name);
497        }
498
499        if (callerFilePath != null) {
500          rc.Report.Warning (7082, 1, callerFilePath.Location,
501            "The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
502            name);
503        }
504      }
505
506      if ((modFlags & Modifier.CallerMemberName) != 0) {
507        if (callerFilePath != null) {
508          rc.Report.Warning (7080, 1, callerFilePath.Location,
509            "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
510            name);
511        }
512
513      }
514    }
515
516    public void ResolveDefaultValue (ResolveContext rc)
517    {
518      //
519      // Default value was specified using an expression
520      //
521      if (default_expr != null) {
522        ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
523        if (attributes != null)
524          ResolveCallerAttributes (rc);
525
526        return;
527      }
528
529      if (attributes == null)
530        return;
531
532      var pa = rc.Module.PredefinedAttributes;
533      var def_attr = attributes.Search (pa.DefaultParameterValue);
534      if (def_attr != null) {
535        if (def_attr.Resolve () == null)
536          return;
537
538        var default_expr_attr = def_attr.GetParameterDefaultValue ();
539        if (default_expr_attr == null)
540          return;
541
542        var dpa_rc = def_attr.CreateResolveContext ();
543        default_expr = default_expr_attr.Resolve (dpa_rc);
544
545        if (default_expr is BoxedCast)
546          default_expr = ((BoxedCast) default_expr).Child;
547
548        Constant c = default_expr as Constant;
549        if (c == null) {
550          if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
551            rc.Report.Error (1910, default_expr.Location,
552              "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
553              default_expr.Type.GetSignatureForError ());
554          } else {
555            rc.Report.Error (1909, default_expr.Location,
556              "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
557              default_expr.Type.GetSignatureForError ());
558          }
559
560          default_expr = null;
561          return;
562        }
563
564        if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
565          (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
566          parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
567          return;
568        }
569
570        //
571        // LAMESPEC: Some really weird csc behaviour which we have to mimic
572        // User operators returning same type as parameter type are considered
573        // valid for this attribute only
574        //
575        // struct S { public static implicit operator S (int i) {} }
576        //
577        // void M ([DefaultParameterValue (3)]S s)
578        //
579        var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
580        if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
581          return;
582        }
583       
584        rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
585        return;
586      }
587
588      var opt_attr = attributes.Search (pa.OptionalParameter);
589      if (opt_attr != null) {
590        default_expr = EmptyExpression.MissingValue;
591      }
592    }
593
594    public bool HasDefaultValue {
595      get { return default_expr != null; }
596    }
597
598    public bool HasExtensionMethodModifier {
599      get { return (modFlags & Modifier.This) != 0; }
600    }
601
602    //
603    // Hoisted parameter variant
604    //
605    public HoistedParameter HoistedVariant {
606      get {
607        return hoisted_variant;
608      }
609      set {
610        hoisted_variant = value;
611      }
612    }
613
614    public Modifier ModFlags {
615      get { return modFlags & ~Modifier.This; }
616    }
617
618    public string Name {
619      get { return name; }
620      set { name = value; }
621    }
622
623    public override AttributeTargets AttributeTargets {
624      get {
625        return AttributeTargets.Parameter;
626      }
627    }
628
629    public void Error_DuplicateName (Report r)
630    {
631      r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
632    }
633
634    public virtual string GetSignatureForError ()
635    {
636      string type_name;
637      if (parameter_type != null)
638        type_name = parameter_type.GetSignatureForError ();
639      else
640        type_name = texpr.GetSignatureForError ();
641
642      string mod = GetModifierSignature (modFlags);
643      if (mod.Length > 0)
644        return String.Concat (mod, " ", type_name);
645
646      return type_name;
647    }
648
649    public static string GetModifierSignature (Modifier mod)
650    {
651      switch (mod) {
652      case Modifier.OUT:
653        return "out";
654      case Modifier.PARAMS:
655        return "params";
656      case Modifier.REF:
657        return "ref";
658      case Modifier.This:
659        return "this";
660      default:
661        return "";
662      }
663    }
664
665    public void IsClsCompliant (IMemberContext ctx)
666    {
667      if (parameter_type.IsCLSCompliant ())
668        return;
669
670      ctx.Module.Compiler.Report.Warning (3001, 1, Location,
671        "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
672    }
673
674    public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
675    {
676      if (builder != null)
677        throw new InternalErrorException ("builder already exists");
678
679      var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
680      if (HasOptionalExpression)
681        pattrs |= ParameterAttributes.Optional;
682
683      if (mb == null)
684        builder = cb.DefineParameter (index, pattrs, Name);
685      else
686        builder = mb.DefineParameter (index, pattrs, Name);
687
688      if (OptAttributes != null)
689        OptAttributes.Emit ();
690
691      if (HasDefaultValue && default_expr.Type != null) {
692        //
693        // Emit constant values for true constants only, the other
694        // constant-like expressions will rely on default value expression
695        //
696        var def_value = DefaultValue;
697        Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
698        if (c != null) {
699          if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
700            pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
701          } else {
702            builder.SetConstant (c.GetValue ());
703          }
704        } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
705          //
706          // Handles special case where default expression is used with value-type or type parameter
707          //
708          // void Foo (S s = default (S)) {}
709          //
710          builder.SetConstant (null);
711        }
712      }
713
714      if (parameter_type != null) {
715        if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
716          pa.Dynamic.EmitAttribute (builder);
717        } else if (parameter_type.HasDynamicElement) {
718          pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
719        }
720      }
721    }
722
723    public Parameter Clone ()
724    {
725      Parameter p = (Parameter) MemberwiseClone ();
726      if (attributes != null)
727        p.attributes = attributes.Clone ();
728
729      return p;
730    }
731
732    public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
733    {
734      if ((modFlags & Modifier.RefOutMask) != 0)
735        ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
736
737      expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
738      expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
739
740      Arguments arguments = new Arguments (2);
741      arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
742      arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
743      return new SimpleAssign (ExpressionTreeVariableReference (),
744        Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
745    }
746
747    public void Emit (EmitContext ec)
748    {
749      ec.EmitArgumentLoad (idx);
750    }
751
752    public void EmitAssign (EmitContext ec)
753    {
754      ec.EmitArgumentStore (idx);
755    }
756
757    public void EmitAddressOf (EmitContext ec)
758    {
759      if ((ModFlags & Modifier.RefOutMask) != 0) {
760        ec.EmitArgumentLoad (idx);
761      } else {
762        ec.EmitArgumentAddress (idx);
763      }
764    }
765
766    public TemporaryVariableReference ExpressionTreeVariableReference ()
767    {
768      return expr_tree_variable;
769    }
770
771    //
772    // System.Linq.Expressions.ParameterExpression type
773    //
774    public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
775    {
776      TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
777      return new TypeExpression (p_type, location);
778    }
779
780    public void SetIndex (int index)
781    {
782      idx = index;
783    }
784
785    public void Warning_UselessOptionalParameter (Report Report)
786    {
787      Report.Warning (1066, 1, Location,
788        "The default value specified for optional parameter `{0}' will never be used",
789        Name);
790    }
791  }
792
793  //
794  // Imported or resolved parameter information
795  //
796  public class ParameterData : IParameterData
797  {
798    readonly string name;
799    readonly Parameter.Modifier modifiers;
800    readonly Expression default_value;
801
802    public ParameterData (string name, Parameter.Modifier modifiers)
803    {
804      this.name = name;
805      this.modifiers = modifiers;
806    }
807
808    public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
809      : this (name, modifiers)
810    {
811      this.default_value = defaultValue;
812    }
813
814    #region IParameterData Members
815
816    public Expression DefaultValue {
817      get { return default_value; }
818    }
819
820    public bool HasExtensionMethodModifier {
821      get { return (modifiers & Parameter.Modifier.This) != 0; }
822    }
823
824    public bool HasDefaultValue {
825      get { return default_value != null; }
826    }
827
828    public Parameter.Modifier ModFlags {
829      get { return modifiers; }
830    }
831
832    public string Name {
833      get { return name; }
834    }
835
836    #endregion
837  }
838
839  public abstract class AParametersCollection
840  {
841    protected bool has_arglist;
842    protected bool has_params;
843
844    // Null object pattern
845    protected IParameterData [] parameters;
846    protected TypeSpec [] types;
847
848    public CallingConventions CallingConvention {
849      get {
850        return has_arglist ?
851          CallingConventions.VarArgs :
852          CallingConventions.Standard;
853      }
854    }
855
856    public int Count {
857      get { return parameters.Length; }
858    }
859
860    public TypeSpec ExtensionMethodType {
861      get {
862        if (Count == 0)
863          return null;
864
865        return FixedParameters [0].HasExtensionMethodModifier ?
866          types [0] : null;
867      }
868    }
869
870    public IParameterData [] FixedParameters {
871      get {
872        return parameters;
873      }
874    }
875
876    public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
877    {
878      return (modFlags & Parameter.Modifier.OUT) != 0 ?
879        ParameterAttributes.Out : ParameterAttributes.None;
880    }
881
882    // Very expensive operation
883    public MetaType[] GetMetaInfo ()
884    {
885      MetaType[] types;
886      if (has_arglist) {
887        if (Count == 1)
888          return MetaType.EmptyTypes;
889
890        types = new MetaType[Count - 1];
891      } else {
892        if (Count == 0)
893          return MetaType.EmptyTypes;
894
895        types = new MetaType[Count];
896      }
897
898      for (int i = 0; i < types.Length; ++i) {
899        types[i] = Types[i].GetMetaInfo ();
900
901        if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
902          continue;
903
904        // TODO MemberCache: Should go to MetaInfo getter
905        types [i] = types [i].MakeByRefType ();
906      }
907
908      return types;
909    }
910
911    //
912    // Returns the parameter information based on the name
913    //
914    public int GetParameterIndexByName (string name)
915    {
916      for (int idx = 0; idx < Count; ++idx) {
917        if (parameters [idx].Name == name)
918          return idx;
919      }
920
921      return -1;
922    }
923
924    public string GetSignatureForDocumentation ()
925    {
926      if (IsEmpty)
927        return string.Empty;
928
929      StringBuilder sb = new StringBuilder ("(");
930      for (int i = 0; i < Count; ++i) {
931        if (i != 0)
932          sb.Append (",");
933
934        sb.Append (types [i].GetSignatureForDocumentation ());
935
936        if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
937          sb.Append ("@");
938      }
939      sb.Append (")");
940
941      return sb.ToString ();
942    }
943
944    public string GetSignatureForError ()
945    {
946      return GetSignatureForError ("(", ")", Count);
947    }
948
949    public string GetSignatureForError (string start, string end, int count)
950    {
951      StringBuilder sb = new StringBuilder (start);
952      for (int i = 0; i < count; ++i) {
953        if (i != 0)
954          sb.Append (", ");
955        sb.Append (ParameterDesc (i));
956      }
957      sb.Append (end);
958      return sb.ToString ();
959    }
960
961    public bool HasArglist {
962      get { return has_arglist; }
963    }
964
965    public bool HasExtensionMethodType {
966      get {
967        if (Count == 0)
968          return false;
969
970        return FixedParameters [0].HasExtensionMethodModifier;
971      }
972    }
973
974    public bool HasParams {
975      get { return has_params; }
976    }
977
978    public bool IsEmpty {
979      get { return parameters.Length == 0; }
980    }
981
982    public AParametersCollection Inflate (TypeParameterInflator inflator)
983    {
984      TypeSpec[] inflated_types = null;
985      bool default_value = false;
986
987      for (int i = 0; i < Count; ++i) {
988        var inflated_param = inflator.Inflate (types[i]);
989        if (inflated_types == null) {
990          if (inflated_param == types[i])
991            continue;
992
993          default_value |= FixedParameters[i].HasDefaultValue;
994          inflated_types = new TypeSpec[types.Length];
995          Array.Copy (types, inflated_types, types.Length);
996        } else {
997          if (inflated_param == types[i])
998            continue;
999
1000          default_value |= FixedParameters[i].HasDefaultValue;
1001        }
1002
1003        inflated_types[i] = inflated_param;
1004      }
1005
1006      if (inflated_types == null)
1007        return this;
1008
1009      var clone = (AParametersCollection) MemberwiseClone ();
1010      clone.types = inflated_types;
1011
1012      //
1013      // Default expression is original expression from the parameter
1014      // declaration context which can be of nested enum in generic class type.
1015      // In such case we end up with expression type of G<T>.E and e.g. parameter
1016      // type of G<int>.E and conversion would fail without inflate in this
1017      // context.
1018      //
1019      if (default_value) {
1020        clone.parameters = new IParameterData[Count];
1021        for (int i = 0; i < Count; ++i) {
1022          var fp = FixedParameters[i];
1023          clone.FixedParameters[i] = fp;
1024
1025          if (!fp.HasDefaultValue)
1026            continue;
1027
1028          var expr = fp.DefaultValue;
1029
1030          if (inflated_types[i] == expr.Type)
1031            continue;
1032
1033          var c = expr as Constant;
1034          if (c != null) {
1035            //
1036            // It may fail we are inflating before type validation is done
1037            //
1038            c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1039            if (c == null)
1040              expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1041            else
1042              expr = c;
1043          } else if (expr is DefaultValueExpression)
1044            expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1045
1046          clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1047        }
1048      }
1049
1050      return clone;
1051    }
1052
1053    public string ParameterDesc (int pos)
1054    {
1055      if (types == null || types [pos] == null)
1056        return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1057
1058      string type = types [pos].GetSignatureForError ();
1059      if (FixedParameters [pos].HasExtensionMethodModifier)
1060        return "this " + type;
1061
1062      var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1063      if (mod == 0)
1064        return type;
1065
1066      return Parameter.GetModifierSignature (mod) + " " + type;
1067    }
1068
1069    public TypeSpec[] Types {
1070      get { return types; }
1071      set { types = value; }
1072    }
1073  }
1074
1075  //
1076  // A collection of imported or resolved parameters
1077  //
1078  public class ParametersImported : AParametersCollection
1079  {
1080    public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1081    {
1082      this.parameters = parameters;
1083      this.types = types;
1084      this.has_arglist = hasArglist;
1085      this.has_params = hasParams;
1086    }
1087
1088    public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1089    {
1090      this.parameters = param;
1091      this.types = types;
1092      this.has_params = hasParams;
1093    }
1094  }
1095
1096  /// <summary>
1097  ///   Represents the methods parameters
1098  /// </summary>
1099  public class ParametersCompiled : AParametersCollection
1100  {
1101    public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1102   
1103    // Used by C# 2.0 delegates
1104    public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1105
1106    private ParametersCompiled ()
1107    {
1108      parameters = new Parameter [0];
1109      types = TypeSpec.EmptyTypes;
1110    }
1111
1112    private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1113    {
1114      this.parameters = parameters;
1115        this.types = types;
1116    }
1117   
1118    public ParametersCompiled (params Parameter[] parameters)
1119    {
1120      if (parameters == null || parameters.Length == 0)
1121        throw new ArgumentException ("Use EmptyReadOnlyParameters");
1122
1123      this.parameters = parameters;
1124      int count = parameters.Length;
1125
1126      for (int i = 0; i < count; i++){
1127        has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1128      }
1129    }
1130
1131    public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1132      this (parameters)
1133    {
1134      this.has_arglist = has_arglist;
1135    }
1136   
1137    public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1138    {
1139      return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1140    }
1141   
1142    public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1143    {
1144      return new ParametersCompiled (parameters, types);
1145    }
1146
1147    public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1148    {
1149      var ptypes = new TypeSpec [parameters.Count + 1];
1150      ptypes [0] = type;
1151      Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1152
1153      var param = new Parameter [ptypes.Length];
1154      param [0] = p;
1155      for (int i = 0; i < parameters.Count; ++i) {
1156        var pi = parameters [i];
1157        param [i + 1] = pi;
1158        pi.SetIndex (i + 1);
1159      }
1160
1161      return ParametersCompiled.CreateFullyResolved (param, ptypes);
1162    }
1163
1164    //
1165    // TODO: This does not fit here, it should go to different version of AParametersCollection
1166    // as the underlying type is not Parameter and some methods will fail to cast
1167    //
1168    public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1169    {
1170      var pd = new ParameterData [types.Length];
1171      for (int i = 0; i < pd.Length; ++i)
1172        pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1173
1174      return new ParametersCompiled (pd, types);
1175    }
1176
1177    public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1178    {
1179      return new ParametersCompiled (
1180        new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1181        null);
1182    }
1183
1184    public void CheckConstraints (IMemberContext mc)
1185    {
1186      foreach (Parameter p in parameters) {
1187        //
1188        // It's null for compiler generated types or special types like __arglist
1189        //
1190        if (p.TypeExpression != null)
1191          ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1192      }
1193    }
1194
1195    //
1196    // Returns non-zero value for equal CLS parameter signatures
1197    //
1198    public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1199    {
1200      int res = 0;
1201
1202      for (int i = 0; i < a.Count; ++i) {
1203        var a_type = a.Types[i];
1204        var b_type = b.Types[i];
1205        if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1206          if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1207            res |= 1;
1208
1209          continue;
1210        }
1211
1212        var ac_a = a_type as ArrayContainer;
1213        if (ac_a == null)
1214          return 0;
1215
1216        var ac_b = b_type as ArrayContainer;
1217        if (ac_b == null)
1218          return 0;
1219
1220        if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1221          res |= 2;
1222          continue;
1223        }
1224
1225        if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1226          res |= 1;
1227          continue;
1228        }
1229
1230        return 0;
1231      }
1232
1233      return res;
1234    }
1235
1236    public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1237    {
1238      return MergeGenerated (ctx, userParams, checkConflicts,
1239        new Parameter [] { compilerParams },
1240        new TypeSpec [] { compilerTypes });
1241    }
1242
1243    //
1244    // Use this method when you merge compiler generated parameters with user parameters
1245    //
1246    public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1247    {
1248      Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1249      userParams.FixedParameters.CopyTo(all_params, 0);
1250
1251      TypeSpec [] all_types;
1252      if (userParams.types != null) {
1253        all_types = new TypeSpec [all_params.Length];
1254        userParams.Types.CopyTo (all_types, 0);
1255      } else {
1256        all_types = null;
1257      }
1258
1259      int last_filled = userParams.Count;
1260      int index = 0;
1261      foreach (Parameter p in compilerParams) {
1262        for (int i = 0; i < last_filled; ++i) {
1263          while (p.Name == all_params [i].Name) {
1264            if (checkConflicts && i < userParams.Count) {
1265              ctx.Report.Error (316, userParams[i].Location,
1266                "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1267            }
1268            p.Name = '_' + p.Name;
1269          }
1270        }
1271        all_params [last_filled] = p;
1272        if (all_types != null)
1273          all_types [last_filled] = compilerTypes [index++];
1274        ++last_filled;
1275      }
1276     
1277      ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1278      parameters.has_params = userParams.has_params;
1279      return parameters;
1280    }
1281
1282    //
1283    // Parameters checks for members which don't have a block
1284    //
1285    public void CheckParameters (MemberCore member)
1286    {
1287      for (int i = 0; i < parameters.Length; ++i) {
1288        var name = parameters[i].Name;
1289        for (int ii = i + 1; ii < parameters.Length; ++ii) {
1290          if (parameters[ii].Name == name)
1291            this[ii].Error_DuplicateName (member.Compiler.Report);
1292        }
1293      }
1294    }
1295
1296    public bool Resolve (IMemberContext ec)
1297    {
1298      if (types != null)
1299        return true;
1300     
1301      types = new TypeSpec [Count];
1302     
1303      bool ok = true;
1304      Parameter p;
1305      for (int i = 0; i < FixedParameters.Length; ++i) {
1306        p = this [i];
1307        TypeSpec t = p.Resolve (ec, i);
1308        if (t == null) {
1309          ok = false;
1310          continue;
1311        }
1312
1313        types [i] = t;
1314      }
1315
1316      return ok;
1317    }
1318
1319    public void ResolveDefaultValues (MemberCore m)
1320    {
1321      ResolveContext rc = null;
1322      for (int i = 0; i < parameters.Length; ++i) {
1323        Parameter p = (Parameter) parameters [i];
1324
1325        //
1326        // Try not to enter default values resolution if there are is not any default value possible
1327        //
1328        if (p.HasDefaultValue || p.OptAttributes != null) {
1329          if (rc == null)
1330            rc = new ResolveContext (m);
1331
1332          p.ResolveDefaultValue (rc);
1333        }
1334      }
1335    }
1336
1337    // Define each type attribute (in/out/ref) and
1338    // the argument names.
1339    public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1340    {
1341      if (Count == 0)
1342        return;
1343
1344      MethodBuilder mb = builder as MethodBuilder;
1345      ConstructorBuilder cb = builder as ConstructorBuilder;
1346      var pa = mc.Module.PredefinedAttributes;
1347
1348      for (int i = 0; i < Count; i++) {
1349        this [i].ApplyAttributes (mb, cb, i + 1, pa);
1350      }
1351    }
1352
1353    public void VerifyClsCompliance (IMemberContext ctx)
1354    {
1355      foreach (Parameter p in FixedParameters)
1356        p.IsClsCompliant (ctx);
1357    }
1358
1359    public Parameter this [int pos] {
1360      get { return (Parameter) parameters [pos]; }
1361    }
1362
1363    public Expression CreateExpressionTree (BlockContext ec, Location loc)
1364    {
1365      var initializers = new ArrayInitializer (Count, loc);
1366      foreach (Parameter p in FixedParameters) {
1367        //
1368        // Each parameter expression is stored to local variable
1369        // to save some memory when referenced later.
1370        //
1371        StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1372        if (se.Resolve (ec)) {
1373          ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1374          ec.CurrentBlock.AddScopeStatement (se);
1375        }
1376       
1377        initializers.Add (p.ExpressionTreeVariableReference ());
1378      }
1379
1380      return new ArrayCreation (
1381        Parameter.ResolveParameterExpressionType (ec, loc),
1382        initializers, loc);
1383    }
1384
1385    public ParametersCompiled Clone ()
1386    {
1387      ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1388
1389      p.parameters = new IParameterData [parameters.Length];
1390      for (int i = 0; i < Count; ++i)
1391        p.parameters [i] = this [i].Clone ();
1392
1393      return p;
1394    }
1395  }
1396
1397  //
1398  // Default parameter value expression. We need this wrapper to handle
1399  // default parameter values of folded constants (e.g. indexer parameters).
1400  // The expression is resolved only once but applied to two methods which
1401  // both share reference to this expression and we ensure that resolving
1402  // this expression always returns same instance
1403  //
1404  public class DefaultParameterValueExpression : CompositeExpression
1405  {
1406    public DefaultParameterValueExpression (Expression expr)
1407      : base (expr)
1408    {
1409    }
1410
1411    public void Resolve (ResolveContext rc, Parameter p)
1412    {
1413      var expr = Resolve (rc);
1414      if (expr == null) {
1415        this.expr = ErrorExpression.Instance;
1416        return;
1417      }
1418
1419      expr = Child;
1420
1421      if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1422        if (!(expr is ErrorExpression)) {
1423          rc.Report.Error (1736, Location,
1424            "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1425            p.Name);
1426        }
1427
1428        return;
1429      }
1430
1431      var parameter_type = p.Type;
1432      if (type == parameter_type)
1433        return;
1434
1435      var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1436      if (res != null) {
1437        if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1438          Nullable.Wrap wrap = (Nullable.Wrap) res;
1439          res = wrap.Child;
1440          if (!(res is Constant)) {
1441            rc.Report.Error (1770, Location,
1442              "The expression being assigned to nullable optional parameter `{0}' must be default value",
1443              p.Name);
1444            return;
1445          }
1446        }
1447
1448        if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1449          rc.Report.Error (1763, Location,
1450            "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1451            p.Name, parameter_type.GetSignatureForError ());
1452
1453          return;
1454        }
1455
1456        this.expr = res;
1457        return;
1458      }
1459
1460      rc.Report.Error (1750, Location,
1461        "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1462        type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1463
1464      this.expr = ErrorExpression.Instance;
1465    }
1466   
1467    public override object Accept (StructuralVisitor visitor)
1468    {
1469      return visitor.Visit (this);
1470    }
1471  }
1472}
Note: See TracBrowser for help on using the repository browser.