1 // ---------------------------------------------------------------------------
2 // Copyright (C) 2006 Microsoft Corporation All Rights Reserved
3 // ---------------------------------------------------------------------------
4 
5 #define CODE_ANALYSIS
6 using System.CodeDom;
7 using System.Collections.Generic;
8 using System.Configuration;
9 using System.Diagnostics;
10 using System.Diagnostics.CodeAnalysis;
11 using System.Globalization;
12 using System.Reflection;
13 using System.Text;
14 using System.Workflow.ComponentModel;
15 using System.Workflow.ComponentModel.Compiler;
16 using System.Workflow.Activities.Common;
17 
18 namespace System.Workflow.Activities.Rules
19 {
20     #region ExpressionInfo
21 
22     // Public base class (which just holds the Type of the expression).
23     public class RuleExpressionInfo
24     {
25         private Type expressionType;
26 
RuleExpressionInfo(Type expressionType)27         public RuleExpressionInfo(Type expressionType)
28         {
29             this.expressionType = expressionType;
30         }
31 
32         public Type ExpressionType
33         {
34             get { return expressionType; }
35         }
36     }
37 
38     // Internal derivation for CodeMethodInvokeExpression
39     internal class RuleMethodInvokeExpressionInfo : RuleExpressionInfo
40     {
41         private MethodInfo methodInfo;
42         private bool needsParamsExpansion;
43 
RuleMethodInvokeExpressionInfo(MethodInfo mi, bool needsParamsExpansion)44         internal RuleMethodInvokeExpressionInfo(MethodInfo mi, bool needsParamsExpansion)
45             : base(mi.ReturnType)
46         {
47             this.methodInfo = mi;
48             this.needsParamsExpansion = needsParamsExpansion;
49         }
50 
51         internal MethodInfo MethodInfo
52         {
53             get { return methodInfo; }
54         }
55 
56         internal bool NeedsParamsExpansion
57         {
58             get { return needsParamsExpansion; }
59         }
60     }
61 
62     // Internal derivation for CodeBinaryExpression
63     internal class RuleBinaryExpressionInfo : RuleExpressionInfo
64     {
65         private Type leftType;
66         private Type rightType;
67         private MethodInfo methodInfo;
68 
69         // no overridden method needed
RuleBinaryExpressionInfo(Type lhsType, Type rhsType, Type resultType)70         internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, Type resultType)
71             : base(resultType)
72         {
73             this.leftType = lhsType;
74             this.rightType = rhsType;
75         }
76 
77         // overridden method found
RuleBinaryExpressionInfo(Type lhsType, Type rhsType, MethodInfo mi)78         internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, MethodInfo mi)
79             : base(mi.ReturnType)
80         {
81             this.leftType = lhsType;
82             this.rightType = rhsType;
83             this.methodInfo = mi;
84         }
85 
86         internal Type LeftType
87         {
88             get { return leftType; }
89         }
90 
91         internal Type RightType
92         {
93             get { return rightType; }
94         }
95 
96         internal MethodInfo MethodInfo
97         {
98             get { return methodInfo; }
99         }
100     }
101 
102     // Internal derivation for CodeFieldReferenceExpression
103     internal class RuleFieldExpressionInfo : RuleExpressionInfo
104     {
105         private FieldInfo fieldInfo;
106 
RuleFieldExpressionInfo(FieldInfo fi)107         internal RuleFieldExpressionInfo(FieldInfo fi)
108             : base(fi.FieldType)
109         {
110             fieldInfo = fi;
111         }
112 
113         internal FieldInfo FieldInfo
114         {
115             get { return fieldInfo; }
116         }
117     }
118 
119     // Internal derivation for CodePropertyReferenceExpression
120     internal class RulePropertyExpressionInfo : RuleExpressionInfo
121     {
122         private PropertyInfo propertyInfo;
123         private bool needsParamsExpansion;
124 
125         // Note that the type pi.PropertyType may differ from the "exprType" argument if this
126         // property is a Bind.
RulePropertyExpressionInfo(PropertyInfo pi, Type exprType, bool needsParamsExpansion)127         internal RulePropertyExpressionInfo(PropertyInfo pi, Type exprType, bool needsParamsExpansion)
128             : base(exprType)
129         {
130             this.propertyInfo = pi;
131             this.needsParamsExpansion = needsParamsExpansion;
132         }
133 
134         internal PropertyInfo PropertyInfo
135         {
136             get { return propertyInfo; }
137         }
138 
139         internal bool NeedsParamsExpansion
140         {
141             get { return needsParamsExpansion; }
142         }
143     }
144 
145     // Internal derivation for CodeMethodInvokeExpression
146     internal class RuleConstructorExpressionInfo : RuleExpressionInfo
147     {
148         private ConstructorInfo constructorInfo;
149         private bool needsParamsExpansion;
150 
RuleConstructorExpressionInfo(ConstructorInfo ci, bool needsParamsExpansion)151         internal RuleConstructorExpressionInfo(ConstructorInfo ci, bool needsParamsExpansion)
152             : base(ci.DeclaringType)
153         {
154             this.constructorInfo = ci;
155             this.needsParamsExpansion = needsParamsExpansion;
156         }
157 
158         internal ConstructorInfo ConstructorInfo
159         {
160             get { return constructorInfo; }
161         }
162 
163         internal bool NeedsParamsExpansion
164         {
165             get { return needsParamsExpansion; }
166         }
167     }
168 
169     internal class ExtensionMethodInfo : MethodInfo
170     {
171         MethodInfo actualMethod;
172         int actualParameterLength;
173         ParameterInfo[] expectedParameters;
174         Type assumedDeclaringType;
175         bool hasOutOrRefParameters = false;
176 
ExtensionMethodInfo(MethodInfo method, ParameterInfo[] actualParameters)177         public ExtensionMethodInfo(MethodInfo method, ParameterInfo[] actualParameters)
178             : base()
179         {
180             Debug.Assert(method.IsStatic, "Expected static method as an extension method");
181 
182             actualMethod = method;
183             // modify parameters
184             actualParameterLength = actualParameters.Length;
185             if (actualParameterLength < 2)
186                 expectedParameters = new ParameterInfo[0];
187             else
188             {
189                 expectedParameters = new ParameterInfo[actualParameterLength - 1];
190                 Array.Copy(actualParameters, 1, expectedParameters, 0, actualParameterLength - 1);
191                 foreach (ParameterInfo pi in expectedParameters)
192                 {
193                     if (pi.ParameterType.IsByRef)
194                         hasOutOrRefParameters = true;
195                 }
196             }
197             // get the type we pretend this method is on (which happens to be the first actual parameter)
198             assumedDeclaringType = actualParameters[0].ParameterType;
199         }
200 
GetBaseDefinition()201         public override MethodInfo GetBaseDefinition()
202         {
203             return actualMethod.GetBaseDefinition();
204         }
205 
206         public override ICustomAttributeProvider ReturnTypeCustomAttributes
207         {
208             get { return actualMethod.ReturnTypeCustomAttributes; }
209         }
210 
211         public override MethodAttributes Attributes
212         {
213             get { return actualMethod.Attributes & ~MethodAttributes.Static; }
214         }
215 
GetMethodImplementationFlags()216         public override MethodImplAttributes GetMethodImplementationFlags()
217         {
218             return actualMethod.GetMethodImplementationFlags();
219         }
220 
GetParameters()221         public override ParameterInfo[] GetParameters()
222         {
223             return expectedParameters;
224         }
225 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)226         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
227         {
228             object[] actualParameters = new object[actualParameterLength];
229             if (actualParameterLength > 1)
230                 Array.Copy(parameters, 0, actualParameters, 1, actualParameterLength - 1);
231             if (obj == null)
232                 actualParameters[0] = null;
233             else
234                 actualParameters[0] = Executor.AdjustType(obj.GetType(), obj, assumedDeclaringType);
235             object result = actualMethod.Invoke(null, invokeAttr, binder, actualParameters, culture);
236             // may be out/ref parameters, so copy back the results
237             if (hasOutOrRefParameters)
238                 Array.Copy(actualParameters, 1, parameters, 0, actualParameterLength - 1);
239             return result;
240         }
241 
242         public override RuntimeMethodHandle MethodHandle
243         {
244             get { return actualMethod.MethodHandle; }
245         }
246 
247         public override Type DeclaringType
248         {
249             get { return actualMethod.DeclaringType; }
250         }
251 
252         public Type AssumedDeclaringType
253         {
254             get { return assumedDeclaringType; }
255         }
256 
GetCustomAttributes(Type attributeType, bool inherit)257         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
258         {
259             return actualMethod.GetCustomAttributes(attributeType, inherit);
260         }
261 
GetCustomAttributes(bool inherit)262         public override object[] GetCustomAttributes(bool inherit)
263         {
264             return actualMethod.GetCustomAttributes(inherit);
265         }
266 
IsDefined(Type attributeType, bool inherit)267         public override bool IsDefined(Type attributeType, bool inherit)
268         {
269             return actualMethod.IsDefined(attributeType, inherit);
270         }
271 
272         public override string Name
273         {
274             get { return actualMethod.Name; }
275         }
276 
277         public override Type ReflectedType
278         {
279             get { return actualMethod.ReflectedType; }
280         }
281 
282         public override Type ReturnType
283         {
284             get { return actualMethod.ReturnType; }
285         }
286     }
287 
288     internal class SimpleParameterInfo : ParameterInfo
289     {
290         // only thing we look at is ParameterType, so no need to override anything else
291         Type parameterType;
292 
SimpleParameterInfo(ParameterInfo parameter)293         public SimpleParameterInfo(ParameterInfo parameter)
294             : base()
295         {
296             parameterType = typeof(Nullable<>).MakeGenericType(parameter.ParameterType);
297         }
298 
SimpleParameterInfo(Type parameter)299         public SimpleParameterInfo(Type parameter)
300             : base()
301         {
302             parameterType = parameter;
303         }
304 
305         public override Type ParameterType
306         {
307             get
308             {
309                 return parameterType;
310             }
311         }
312     }
313 
314     internal abstract class BaseMethodInfo : MethodInfo
315     {
316         protected MethodInfo actualMethod;
317         protected ParameterInfo[] expectedParameters;
318         protected Type resultType;
319 
BaseMethodInfo(MethodInfo method)320         public BaseMethodInfo(MethodInfo method)
321             : base()
322         {
323             Debug.Assert(method.IsStatic, "Expected static method as an lifted method");
324             actualMethod = method;
325             resultType = method.ReturnType;
326             expectedParameters = method.GetParameters();
327         }
328 
GetBaseDefinition()329         public override MethodInfo GetBaseDefinition()
330         {
331             return actualMethod.GetBaseDefinition();
332         }
333 
334         public override ICustomAttributeProvider ReturnTypeCustomAttributes
335         {
336             get { return actualMethod.ReturnTypeCustomAttributes; }
337         }
338 
339         public override MethodAttributes Attributes
340         {
341             get { return actualMethod.Attributes & ~MethodAttributes.Static; }
342         }
343 
GetMethodImplementationFlags()344         public override MethodImplAttributes GetMethodImplementationFlags()
345         {
346             return actualMethod.GetMethodImplementationFlags();
347         }
348 
GetParameters()349         public override ParameterInfo[] GetParameters()
350         {
351             return expectedParameters;
352         }
353 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)354         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
355         {
356             throw new NotImplementedException();
357         }
358 
359         public override RuntimeMethodHandle MethodHandle
360         {
361             get { return actualMethod.MethodHandle; }
362         }
363 
364         public override Type DeclaringType
365         {
366             get { return actualMethod.DeclaringType; }
367         }
368 
GetCustomAttributes(Type attributeType, bool inherit)369         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
370         {
371             return actualMethod.GetCustomAttributes(attributeType, inherit);
372         }
373 
GetCustomAttributes(bool inherit)374         public override object[] GetCustomAttributes(bool inherit)
375         {
376             return actualMethod.GetCustomAttributes(inherit);
377         }
378 
IsDefined(Type attributeType, bool inherit)379         public override bool IsDefined(Type attributeType, bool inherit)
380         {
381             return actualMethod.IsDefined(attributeType, inherit);
382         }
383 
384         public override string Name
385         {
386             get { return actualMethod.Name; }
387         }
388 
389         public override Type ReflectedType
390         {
391             get { return actualMethod.ReflectedType; }
392         }
393 
394         public override Type ReturnType
395         {
396             get { return resultType; }
397         }
398 
Equals(object obj)399         public override bool Equals(object obj)
400         {
401             BaseMethodInfo other = obj as BaseMethodInfo;
402             if ((other == null)
403                 || (actualMethod != other.actualMethod)
404                 || (resultType != other.resultType)
405                 || (expectedParameters.Length != other.expectedParameters.Length))
406                 return false;
407             for (int i = 0; i < expectedParameters.Length; ++i)
408                 if (expectedParameters[i].ParameterType != other.expectedParameters[i].ParameterType)
409                     return false;
410             return true;
411         }
412 
GetHashCode()413         public override int GetHashCode()
414         {
415             int result = actualMethod.GetHashCode() ^ resultType.GetHashCode();
416             for (int i = 0; i < expectedParameters.Length; ++i)
417                 result ^= expectedParameters[i].GetHashCode();
418             return result;
419         }
420     }
421 
422     internal class LiftedConversionMethodInfo : BaseMethodInfo
423     {
LiftedConversionMethodInfo(MethodInfo method)424         public LiftedConversionMethodInfo(MethodInfo method)
425             : base(method)
426         {
427             Debug.Assert(expectedParameters.Length == 1, "not 1 parameters");
428 
429             // modify result
430             resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType);
431 
432             // modify parameter (exactly 1)
433             ParameterInfo[] actualParameters = method.GetParameters();
434             expectedParameters = new ParameterInfo[1];
435             expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
436         }
437 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)438         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
439         {
440             // null in, then result is null
441             if (parameters[0] == null)
442                 return Activator.CreateInstance(resultType);
443 
444             // invoke the conversion from S -> T
445             object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
446             // return a T?
447             return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
448         }
449     }
450 
451     internal class LiftedArithmeticOperatorMethodInfo : BaseMethodInfo
452     {
LiftedArithmeticOperatorMethodInfo(MethodInfo method)453         public LiftedArithmeticOperatorMethodInfo(MethodInfo method)
454             : base(method)
455         {
456             Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");
457 
458             // modify parameters (exactly 2, both need to be lifted)
459             ParameterInfo[] actualParameters = method.GetParameters();
460             expectedParameters = new ParameterInfo[2];
461             expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
462             expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
463 
464             // modify result
465             resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType);
466         }
467 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)468         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
469         {
470             // null in, then result is null
471             if (parameters[0] == null)
472                 return null;
473             if (parameters[1] == null)
474                 return null;
475 
476             // apply the underlying operator
477             object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
478             // return a T?
479             return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
480         }
481     }
482 
483     internal class LiftedEqualityOperatorMethodInfo : BaseMethodInfo
484     {
LiftedEqualityOperatorMethodInfo(MethodInfo method)485         public LiftedEqualityOperatorMethodInfo(MethodInfo method)
486             : base(method)
487         {
488             Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
489             Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");
490 
491             // modify parameters (exactly 2, both need to be lifted)
492             ParameterInfo[] actualParameters = method.GetParameters();
493             expectedParameters = new ParameterInfo[2];
494             expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
495             expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
496 
497             // set the result type
498             resultType = typeof(bool);
499         }
500 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)501         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
502         {
503             // null == null is true, null == something else is false, else call method
504             if (parameters[0] == null)
505                 return (parameters[1] == null);
506             else if (parameters[1] == null)
507                 return false;
508 
509             // invoke the actual comparison (parameters are unwrapped)
510             return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
511         }
512     }
513 
514     internal class LiftedRelationalOperatorMethodInfo : BaseMethodInfo
515     {
LiftedRelationalOperatorMethodInfo(MethodInfo method)516         public LiftedRelationalOperatorMethodInfo(MethodInfo method)
517             : base(method)
518         {
519             Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
520             Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");
521 
522             // modify parameters (exactly 2, both need to be lifted)
523             ParameterInfo[] actualParameters = method.GetParameters();
524             expectedParameters = new ParameterInfo[2];
525             expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
526             expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
527 
528             // set the result type
529             resultType = typeof(bool);
530         }
531 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)532         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
533         {
534             // if either parameter is null, then result is false
535             if (parameters[0] == null)
536                 return false;
537             if (parameters[1] == null)
538                 return false;
539 
540             // invoke the actual comparison (parameters are unwrapped)
541             return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
542         }
543     }
544 
545     internal class EnumOperationMethodInfo : MethodInfo
546     {
547         CodeBinaryOperatorType op;
548         ParameterInfo[] expectedParameters;
549         Type resultType;        // may be nullable, enum, or value type
550         bool resultIsNullable;  // true if resultType is nullable
551 
552         Type lhsBaseType;       // non-Nullable, may be enum
553         Type rhsBaseType;
554         Type resultBaseType;
555 
556         Type lhsRootType;       // underlying type (int, long, ushort, etc)
557         Type rhsRootType;
558         Type resultRootType;
559 
560         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
EnumOperationMethodInfo(Type lhs, CodeBinaryOperatorType operation, Type rhs, bool isZero)561         public EnumOperationMethodInfo(Type lhs, CodeBinaryOperatorType operation, Type rhs, bool isZero)
562         {
563             // only 5 arithmetic cases (U = underlying type of E):
564             //    E = E + U
565             //    E = U + E
566             //    U = E - E
567             //    E = E - U
568             //    E = U - E
569             // plus 5 comparison cases
570             //    E == E
571             //    E < E
572             //    E <= E
573             //    E > E
574             //    E >= E
575             // either E can be nullable
576 
577             op = operation;
578 
579             // parameters are easy -- they are the same as the type passed in
580             expectedParameters = new ParameterInfo[2];
581             expectedParameters[0] = new SimpleParameterInfo(lhs);
582             expectedParameters[1] = new SimpleParameterInfo(rhs);
583 
584             // compute return type (depends on type of operation)
585             // start by getting the types without Nullable<>
586             bool lhsNullable = ConditionHelper.IsNullableValueType(lhs);
587             bool rhsNullable = ConditionHelper.IsNullableValueType(rhs);
588             lhsBaseType = (lhsNullable) ? Nullable.GetUnderlyingType(lhs) : lhs;
589             rhsBaseType = (rhsNullable) ? Nullable.GetUnderlyingType(rhs) : rhs;
590             // determine the underlying types for both sides
591             if (lhsBaseType.IsEnum)
592                 lhsRootType = EnumHelper.GetUnderlyingType(lhsBaseType);
593             else
594                 lhsRootType = lhsBaseType;
595 
596             if (rhsBaseType.IsEnum)
597                 rhsRootType = EnumHelper.GetUnderlyingType(rhsBaseType);
598             else
599                 rhsRootType = rhsBaseType;
600 
601             switch (op)
602             {
603                 case CodeBinaryOperatorType.Add:
604                     // add always produces an enum, except enum + enum
605                     if ((lhsBaseType.IsEnum) && (rhs.IsEnum))
606                         resultBaseType = lhsRootType;
607                     else if (lhsBaseType.IsEnum)
608                         resultBaseType = lhsBaseType;
609                     else
610                         resultBaseType = rhsBaseType;
611                     // if either side is nullable, result is nullable
612                     resultIsNullable = (lhsNullable || rhsNullable);
613                     resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType;
614                     break;
615                 case CodeBinaryOperatorType.Subtract:
616                     // subtract can be an enum or the underlying type
617                     if (rhsBaseType.IsEnum && lhsBaseType.IsEnum)
618                     {
619                         resultRootType = rhsRootType;
620                         resultBaseType = rhsRootType;
621                     }
622                     else if (lhsBaseType.IsEnum)
623                     {
624                         // special case for E - 0
625                         // if 0 is the underlying type, then use E - U
626                         // if not the underlying type, then 0 becomes E, use E - E
627                         resultRootType = lhsRootType;
628                         if (isZero && rhsBaseType != lhsRootType)
629                             resultBaseType = lhsRootType;
630                         else
631                             resultBaseType = lhsBaseType;
632                     }
633                     else    // rhsType.IsEnum
634                     {
635                         // special case for 0 - E
636                         // in all cases 0 becomes E, use E - E
637                         resultRootType = rhsRootType;
638                         if (isZero)
639                             resultBaseType = rhsRootType;
640                         else
641                             resultBaseType = rhsBaseType;
642                     }
643                     resultIsNullable = (lhsNullable || rhsNullable);
644                     resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType;
645                     break;
646                 case CodeBinaryOperatorType.ValueEquality:
647                 case CodeBinaryOperatorType.LessThan:
648                 case CodeBinaryOperatorType.LessThanOrEqual:
649                 case CodeBinaryOperatorType.GreaterThan:
650                 case CodeBinaryOperatorType.GreaterThanOrEqual:
651                     resultType = typeof(bool);
652                     break;
653             }
654         }
655 
GetBaseDefinition()656         public override MethodInfo GetBaseDefinition()
657         {
658             return null;
659         }
660 
661         public override ICustomAttributeProvider ReturnTypeCustomAttributes
662         {
663             get { return null; }
664         }
665 
666         public override MethodAttributes Attributes
667         {
668             get { return MethodAttributes.Static; }
669         }
670 
GetMethodImplementationFlags()671         public override MethodImplAttributes GetMethodImplementationFlags()
672         {
673             return MethodImplAttributes.Runtime;
674         }
675 
GetParameters()676         public override ParameterInfo[] GetParameters()
677         {
678             return expectedParameters;
679         }
680 
681         [SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)682         public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
683         {
684             // we should get passed in 2 values that correspond to the parameter types
685 
686             object result;
687             ArithmeticLiteral leftArithmetic, rightArithmetic;
688             Literal leftLiteral, rightLiteral;
689 
690             // for design-time types we couldn't find the underlying type, so do it now
691             if (lhsRootType == null)
692                 lhsRootType = Enum.GetUnderlyingType(lhsBaseType);
693             if (rhsRootType == null)
694                 rhsRootType = Enum.GetUnderlyingType(rhsBaseType);
695 
696             switch (op)
697             {
698                 case CodeBinaryOperatorType.Add:
699                     // if either is null, then the result is null
700                     if ((parameters[0] == null) || (parameters[1] == null))
701                         return null;
702                     leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsRootType, parameters[0]);
703                     rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsRootType, parameters[1]);
704                     result = leftArithmetic.Add(rightArithmetic);
705                     result = Executor.AdjustType(result.GetType(), result, resultBaseType);
706                     if (resultIsNullable)
707                         result = Activator.CreateInstance(resultType, result);
708                     return result;
709                 case CodeBinaryOperatorType.Subtract:
710                     // if either is null, then the result is null
711                     if ((parameters[0] == null) || (parameters[1] == null))
712                         return null;
713                     leftArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
714                         Executor.AdjustType(lhsRootType, parameters[0], resultRootType));
715                     rightArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
716                         Executor.AdjustType(rhsRootType, parameters[1], resultRootType));
717                     result = leftArithmetic.Subtract(rightArithmetic);
718                     result = Executor.AdjustType(result.GetType(), result, resultBaseType);
719                     if (resultIsNullable)
720                         result = Activator.CreateInstance(resultType, result);
721                     return result;
722 
723                 case CodeBinaryOperatorType.ValueEquality:
724                     leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
725                     rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
726                     return leftLiteral.Equal(rightLiteral);
727                 case CodeBinaryOperatorType.LessThan:
728                     leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
729                     rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
730                     return leftLiteral.LessThan(rightLiteral);
731                 case CodeBinaryOperatorType.LessThanOrEqual:
732                     leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
733                     rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
734                     return leftLiteral.LessThanOrEqual(rightLiteral);
735                 case CodeBinaryOperatorType.GreaterThan:
736                     leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
737                     rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
738                     return leftLiteral.GreaterThan(rightLiteral);
739                 case CodeBinaryOperatorType.GreaterThanOrEqual:
740                     leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
741                     rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
742                     return leftLiteral.GreaterThanOrEqual(rightLiteral);
743             }
744             string message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, op.ToString());
745             throw new RuleEvaluationException(message);
746         }
747 
748         public override RuntimeMethodHandle MethodHandle
749         {
750             get { return new RuntimeMethodHandle(); }
751         }
752 
753         public override Type DeclaringType
754         {
755             get { return typeof(Enum); }
756         }
757 
GetCustomAttributes(Type attributeType, bool inherit)758         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
759         {
760             return new object[0];
761         }
762 
GetCustomAttributes(bool inherit)763         public override object[] GetCustomAttributes(bool inherit)
764         {
765             return new object[0];
766         }
767 
IsDefined(Type attributeType, bool inherit)768         public override bool IsDefined(Type attributeType, bool inherit)
769         {
770             return true;
771         }
772 
773         public override string Name
774         {
775             get { return "op_Enum"; }
776         }
777 
778         public override Type ReflectedType
779         {
780             get { return resultType; }
781         }
782 
783         public override Type ReturnType
784         {
785             get { return resultType; }
786         }
787     }
788     #endregion
789 
790     #region SimpleRunTimeTypeProvider
791 
792     internal class SimpleRunTimeTypeProvider : ITypeProvider
793     {
794         private Assembly root;
795         private List<Assembly> references;
796 
SimpleRunTimeTypeProvider(Assembly startingAssembly)797         internal SimpleRunTimeTypeProvider(Assembly startingAssembly)
798         {
799             root = startingAssembly;
800         }
801 
GetType(string name)802         public Type GetType(string name)
803         {
804             return GetType(name, false);
805         }
806 
GetType(string name, bool throwOnError)807         public Type GetType(string name, bool throwOnError)
808         {
809             // is the type available in the main workflow assembly?
810             Type type = root.GetType(name, throwOnError, false);
811             if (type != null)
812                 return type;
813 
814             // now try mscorlib or this assembly
815             // (or if the name is an assembly qualified name)
816             type = Type.GetType(name, throwOnError, false);
817             if (type != null)
818                 return type;
819 
820             // no luck so far, so try all referenced assemblies
821             foreach (Assembly a in ReferencedAssemblies)
822             {
823                 type = a.GetType(name, throwOnError, false);
824                 if (type != null)
825                     return type;
826             }
827 
828             // keep going by trying all loaded assemblies
829             Assembly[] loaded = AppDomain.CurrentDomain.GetAssemblies();
830             for (int i = 0; i < loaded.Length; ++i)
831             {
832                 type = loaded[i].GetType(name, throwOnError, false);
833                 if (type != null)
834                     return type;
835             }
836             return null;
837         }
838 
GetTypes()839         public Type[] GetTypes()
840         {
841             List<Type> types = new List<Type>();
842             try
843             {
844                 types.AddRange(root.GetTypes());
845             }
846             catch (ReflectionTypeLoadException e)
847             {
848                 // problems loading all the types, take what we can get
849                 foreach (Type type in e.Types)
850                     if (type != null)
851                         types.Add(type);
852             }
853             foreach (Assembly a in ReferencedAssemblies)
854             {
855                 try
856                 {
857                     types.AddRange(a.GetTypes());
858                 }
859                 catch (ReflectionTypeLoadException e)
860                 {
861                     // problems loading all the types, take what we can get
862                     foreach (Type type in e.Types)
863                         if (type != null)
864                             types.Add(type);
865                 }
866             }
867             return types.ToArray();
868         }
869 
870         public Assembly LocalAssembly
871         {
872             get { return root; }
873         }
874 
875         public ICollection<Assembly> ReferencedAssemblies
876         {
877             get
878             {
879                 // references is created on demand, does not include root
880                 if (references == null)
881                 {
882                     List<Assembly> list = new List<Assembly>();
883                     foreach (AssemblyName a in root.GetReferencedAssemblies())
884                     {
885                         list.Add(Assembly.Load(a));
886                     }
887                     references = list;
888                 }
889                 return references;
890             }
891         }
892 
893         public IDictionary<object, Exception> TypeLoadErrors
894         {
895             get
896             {
897                 // we never use this method, so add use of EventHandlers to keep compiler happy
898                 TypesChanged.Invoke(this, null);
899                 TypeLoadErrorsChanged.Invoke(this, null);
900                 return null;
901             }
902         }
903 
904         public event EventHandler TypesChanged;
905 
906         public event EventHandler TypeLoadErrorsChanged;
907     }
908     #endregion
909 
910     #region RuleValidation
911 
912     public class RuleValidation
913     {
914         private Type thisType;
915         private ITypeProvider typeProvider;
916         private ValidationErrorCollection errors = new ValidationErrorCollection();
917         private Dictionary<string, Type> typesUsed = new Dictionary<string, Type>(16);
918         private Dictionary<string, Type> typesUsedAuthorized;
919         private Stack<CodeExpression> activeParentNodes = new Stack<CodeExpression>();
920         private Dictionary<CodeExpression, RuleExpressionInfo> expressionInfoMap = new Dictionary<CodeExpression, RuleExpressionInfo>();
921         private Dictionary<CodeTypeReference, Type> typeRefMap = new Dictionary<CodeTypeReference, Type>();
922         private bool checkStaticType;
923         private IList<AuthorizedType> authorizedTypes;
924         private static readonly Type voidType = typeof(void);
925         private static string voidTypeName = voidType.AssemblyQualifiedName;
926 
927         #region Constructors
928 
929         // Validate at design time.
RuleValidation(Activity activity, ITypeProvider typeProvider, bool checkStaticType)930         public RuleValidation(Activity activity, ITypeProvider typeProvider, bool checkStaticType)
931         {
932             if (activity == null)
933                 throw new ArgumentNullException("activity");
934             if (typeProvider == null)
935                 throw new ArgumentNullException("typeProvider");
936 
937             this.thisType = ConditionHelper.GetContextType(typeProvider, activity);
938             this.typeProvider = typeProvider;
939             this.checkStaticType = checkStaticType;
940             if (checkStaticType)
941             {
942                 Debug.Assert(WorkflowCompilationContext.Current != null, "Can't have checkTypes set to true without a context in scope");
943                 this.authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes();
944                 this.typesUsedAuthorized = new Dictionary<string, Type>();
945                 this.typesUsedAuthorized.Add(voidTypeName, voidType);
946             }
947         }
948 
949         // Validate at runtime when we have the actual subject instance.  This is
950         // mostly for conditions used in activities like IfElse.
RuleValidation(object thisObject)951         internal RuleValidation(object thisObject)
952         {
953             if (thisObject == null)
954                 throw new ArgumentNullException("thisObject");
955 
956             this.thisType = thisObject.GetType();
957             this.typeProvider = new SimpleRunTimeTypeProvider(this.thisType.Assembly);
958         }
959 
960         // Validate at runtime when we have just the type.  This is mostly for rules.
RuleValidation(Type thisType, ITypeProvider typeProvider)961         public RuleValidation(Type thisType, ITypeProvider typeProvider)
962         {
963             if (thisType == null)
964                 throw new ArgumentNullException("thisType");
965 
966             this.thisType = thisType;
967             this.typeProvider = (typeProvider != null) ? typeProvider : new SimpleRunTimeTypeProvider(this.thisType.Assembly);
968         }
969 
970         #endregion
971 
972         #region Internal validation methods
973 
ValidateConditionExpression(CodeExpression expression)974         internal bool ValidateConditionExpression(CodeExpression expression)
975         {
976             if (expression == null)
977                 throw new ArgumentNullException("expression");
978 
979             // Run the validation pass.
980             RuleExpressionInfo exprInfo = RuleExpressionWalker.Validate(this, expression, false);
981             if (exprInfo == null)
982                 return false;
983 
984             Type resultType = exprInfo.ExpressionType;
985             if (!IsValidBooleanResult(resultType))
986             {
987                 // not a boolean, so complain unless another error may have caused this problem
988                 if (resultType != null || Errors.Count == 0)
989                 {
990                     string message = Messages.ConditionMustBeBoolean;
991                     ValidationError error = new ValidationError(message, ErrorNumbers.Error_ConditionMustBeBoolean);
992                     error.UserData[RuleUserDataKeys.ErrorObject] = expression;
993                     Errors.Add(error);
994                 }
995             }
996 
997             return Errors.Count == 0;
998         }
999 
IsValidBooleanResult(Type type)1000         internal static bool IsValidBooleanResult(Type type)
1001         {
1002             return ((type == typeof(bool))
1003                 || (type == typeof(bool?))
1004                 || (ImplicitConversion(type, typeof(bool))));
1005         }
1006 
IsPrivate(MethodInfo methodInfo)1007         internal static bool IsPrivate(MethodInfo methodInfo)
1008         {
1009             return methodInfo.IsPrivate
1010                 || methodInfo.IsFamily
1011                 || methodInfo.IsFamilyOrAssembly
1012                 || methodInfo.IsFamilyAndAssembly;
1013         }
1014 
IsPrivate(FieldInfo fieldInfo)1015         internal static bool IsPrivate(FieldInfo fieldInfo)
1016         {
1017             return fieldInfo.IsPrivate
1018                 || fieldInfo.IsFamily
1019                 || fieldInfo.IsFamilyOrAssembly
1020                 || fieldInfo.IsFamilyAndAssembly;
1021         }
1022 
IsInternal(MethodInfo methodInfo)1023         internal static bool IsInternal(MethodInfo methodInfo)
1024         {
1025             return methodInfo.IsAssembly
1026                 || methodInfo.IsFamilyAndAssembly;
1027         }
1028 
IsInternal(FieldInfo fieldInfo)1029         internal static bool IsInternal(FieldInfo fieldInfo)
1030         {
1031             return fieldInfo.IsAssembly
1032                 || fieldInfo.IsFamilyAndAssembly;
1033         }
1034 
1035         #endregion
1036 
1037         #region Miscellaneous public properties & methods
1038 
1039         public Type ThisType
1040         {
1041             get { return thisType; }
1042         }
1043 
GetTypeProvider()1044         internal ITypeProvider GetTypeProvider()
1045         {
1046             return typeProvider;
1047         }
1048 
1049         public ValidationErrorCollection Errors
1050         {
1051             get { return errors; }
1052         }
1053 
AllowInternalMembers(Type type)1054         internal bool AllowInternalMembers(Type type)
1055         {
1056             return type.Assembly == thisType.Assembly;
1057         }
1058 
AddError(ValidationError error)1059         internal void AddError(ValidationError error)
1060         {
1061             this.Errors.Add(error);
1062         }
1063 
PushParentExpression(CodeExpression newParent)1064         public bool PushParentExpression(CodeExpression newParent)
1065         {
1066             if (newParent == null)
1067                 throw new ArgumentNullException("newParent");
1068 
1069             if (activeParentNodes.Contains(newParent))
1070             {
1071                 string message = string.Format(CultureInfo.CurrentCulture, Messages.CyclicalExpression);
1072                 ValidationError error = new ValidationError(message, ErrorNumbers.Error_CyclicalExpression);
1073                 error.UserData[RuleUserDataKeys.ErrorObject] = newParent;
1074                 Errors.Add(error);
1075                 return false;
1076             }
1077 
1078             activeParentNodes.Push(newParent);
1079             return true;
1080         }
1081 
PopParentExpression()1082         public void PopParentExpression()
1083         {
1084             activeParentNodes.Pop();
1085         }
1086 
1087         // Get the ExpressionInfo associated with a given CodeExpression
ExpressionInfo(CodeExpression expression)1088         public RuleExpressionInfo ExpressionInfo(CodeExpression expression)
1089         {
1090             if (expression == null)
1091                 throw new ArgumentNullException("expression");
1092 
1093             RuleExpressionInfo exprInfo = null;
1094             expressionInfoMap.TryGetValue(expression, out exprInfo);
1095 
1096             return exprInfo;
1097         }
1098 
1099         #endregion
1100 
1101         #region CodeDom Expression Validation methods
1102 
ValidateSubexpression(CodeExpression expr, RuleExpressionInternal ruleExpr, bool isWritten)1103         internal RuleExpressionInfo ValidateSubexpression(CodeExpression expr, RuleExpressionInternal ruleExpr, bool isWritten)
1104         {
1105             Debug.Assert(ruleExpr != null, "Validation::ValidateSubexpression - IRuleExpression is null");
1106             Debug.Assert(expr != null, "Validation::ValidateSubexpression - CodeExpression is null");
1107 
1108             RuleExpressionInfo exprInfo = ruleExpr.Validate(expr, this, isWritten);
1109 
1110             if (exprInfo != null)
1111             {
1112                 // Add the CodeExpression object to the info map.  We don't want to add the IRuleExpression guy
1113                 // as the key, since it might likely be just a tearoff wrapper.
1114                 expressionInfoMap[expr] = exprInfo;
1115             }
1116 
1117             return exprInfo;
1118         }
1119 
TypesAreAssignable(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)1120         internal static bool TypesAreAssignable(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)
1121         {
1122             // determine if rhsType can be implicitly converted to lhsType,
1123             // following the rules in C# specification section 6.1,
1124             // plus support for Nullable<T>
1125 
1126             // all but 6.1.7 handled as a standard implicit conversion
1127             if (StandardImplicitConversion(rhsType, lhsType, rhsExpression, out error))
1128                 return true;
1129             if (error != null)
1130                 return false;
1131 
1132             // no standard implicit conversion works, see if user specified one
1133             // from section 6.4.3, start by determining what types to check
1134             // as we find each type, add the list of implicit conversions available
1135             if (FindImplicitConversion(rhsType, lhsType, out error) == null)
1136                 return false;
1137             return true;
1138         }
1139 
ExplicitConversionSpecified(Type fromType, Type toType, out ValidationError error)1140         internal static bool ExplicitConversionSpecified(Type fromType, Type toType, out ValidationError error)
1141         {
1142             // determine if fromType can be implicitly converted to toType,
1143             // following the rules in C# specification section 6.2
1144 
1145             // start by seeing if there is a standard implicit conversion
1146             if (StandardImplicitConversion(fromType, toType, null, out error))
1147                 return true;
1148             if (error != null)
1149                 return false;
1150 
1151             // explicit numeric conversions
1152             // also handles Enum conversions, since GetTypeCode returns the underlying type
1153             if (fromType.IsValueType && toType.IsValueType && IsExplicitNumericConversion(fromType, toType))
1154                 return true;
1155 
1156             // explicit reference conversions
1157             // this looks like the inverse of implicit conversions
1158             ValidationError dummyError; // so we don't return an error
1159             if (StandardImplicitConversion(toType, fromType, null, out dummyError))
1160                 return true;
1161             // include interface checks
1162             if (toType.IsInterface)
1163             {
1164                 // from any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
1165                 // latter part should be handled by implicit conversion, so we are ok as long as class is not sealed
1166                 if ((fromType.IsClass) && (!fromType.IsSealed))
1167                     return true;
1168                 // from any interface-type S to any interface-type T, provided S is not derived from T.
1169                 // again, if S derived from T, handled by implicit conversion above
1170                 if (fromType.IsInterface)
1171                     return true;
1172             }
1173             if (fromType.IsInterface)
1174             {
1175                 // from any interface-type S to any class-type T, provided T is not sealed or provided T implements S.
1176                 if ((toType.IsClass) && ((!toType.IsSealed) || (InterfaceMatch(toType.GetInterfaces(), fromType))))
1177                     return true;
1178             }
1179 
1180             // no look for user-defined conversions
1181             // from section 6.4.4, start by determining what types to check
1182             // as we find each type, add the list of implicit conversions available
1183             if (FindExplicitConversion(fromType, toType, out error) == null)
1184                 return false;
1185             return true;
1186         }
1187 
InterfaceMatch(Type[] types, Type fromType)1188         private static bool InterfaceMatch(Type[] types, Type fromType)
1189         {
1190             foreach (Type t in types)
1191             {
1192                 if (t == fromType)
1193                     return true;
1194             }
1195             return false;
1196         }
1197 
1198         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
FindImplicitConversion(Type fromType, Type toType, out ValidationError error)1199         internal static MethodInfo FindImplicitConversion(Type fromType, Type toType, out ValidationError error)
1200         {
1201             List<MethodInfo> candidates = new List<MethodInfo>();
1202 
1203             bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
1204             bool toIsNullable = ConditionHelper.IsNullableValueType(toType);
1205             Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType;
1206             Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
1207 
1208             if (fromType0.IsClass)
1209             {
1210                 AddImplicitConversions(fromType0, fromType, toType, candidates);
1211                 Type baseType = fromType0.BaseType;
1212                 while ((baseType != null) && (baseType != typeof(object)))
1213                 {
1214                     AddImplicitConversions(baseType, fromType, toType, candidates);
1215                     baseType = baseType.BaseType;
1216                 }
1217             }
1218             else if (IsStruct(fromType0))
1219             {
1220                 AddImplicitConversions(fromType0, fromType, toType, candidates);
1221             }
1222             if ((toType0.IsClass) || (IsStruct(toType0)))
1223             {
1224                 AddImplicitConversions(toType0, fromType, toType, candidates);
1225             }
1226 
1227             // if both types are nullable, add the lifted operators
1228             if (fromIsNullable && toIsNullable)
1229             {
1230                 // start by finding all the conversion operators from S0 -> T0
1231                 List<MethodInfo> liftedCandidates = new List<MethodInfo>();
1232                 if (fromType0.IsClass)
1233                 {
1234                     AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
1235                     Type baseType = fromType0.BaseType;
1236                     while ((baseType != null) && (baseType != typeof(object)))
1237                     {
1238                         AddImplicitConversions(baseType, fromType0, toType0, liftedCandidates);
1239                         baseType = baseType.BaseType;
1240                     }
1241                 }
1242                 else if (IsStruct(fromType0))
1243                 {
1244                     AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
1245                 }
1246                 if ((toType0.IsClass) || (IsStruct(toType0)))
1247                 {
1248                     AddImplicitConversions(toType0, fromType0, toType0, liftedCandidates);
1249                 }
1250 
1251                 // add them all to the candidates list as lifted methods (which wraps them appropriately)
1252                 foreach (MethodInfo mi in liftedCandidates)
1253                 {
1254                     // only lift candidates that convert from a non-nullable value type
1255                     // to a non-nullable value type
1256                     ParameterInfo[] parameters = mi.GetParameters();
1257                     if (ConditionHelper.IsNonNullableValueType(mi.ReturnType) && ConditionHelper.IsNonNullableValueType(parameters[0].ParameterType))
1258                         candidates.Add(new LiftedConversionMethodInfo(mi));
1259                 }
1260             }
1261 
1262             if (candidates.Count == 0)
1263             {
1264                 // no overrides, so must be false
1265                 string message = string.Format(CultureInfo.CurrentCulture,
1266                     Messages.NoConversion,
1267                     RuleDecompiler.DecompileType(fromType),
1268                     RuleDecompiler.DecompileType(toType));
1269                 error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
1270                 return null;
1271             }
1272 
1273             // find the most specific source type
1274             ValidationError dummyError; // so we don't return an error
1275             Type sx = candidates[0].GetParameters()[0].ParameterType;
1276             if (sx != fromType)
1277             {
1278                 for (int i = 1; i < candidates.Count; ++i)
1279                 {
1280                     Type testType = candidates[i].GetParameters()[0].ParameterType;
1281                     if (testType == fromType)
1282                     {
1283                         // we have a match with the source type, so that's the correct answer
1284                         sx = fromType;
1285                         break;
1286                     }
1287                     if (StandardImplicitConversion(testType, sx, null, out dummyError))
1288                         sx = testType;
1289                 }
1290             }
1291 
1292             // find the most specific target type
1293             Type tx = candidates[0].ReturnType;
1294             if (tx != toType)
1295             {
1296                 for (int i = 1; i < candidates.Count; ++i)
1297                 {
1298                     Type testType = candidates[i].ReturnType;
1299                     if (testType == toType)
1300                     {
1301                         // we have a match with the target type, so that's the correct answer
1302                         tx = toType;
1303                         break;
1304                     }
1305                     if (StandardImplicitConversion(tx, testType, null, out dummyError))
1306                         tx = testType;
1307                 }
1308             }
1309 
1310             // see how many candidates convert from sx to tx, ignoring lifted methods
1311             int numMatches = 0;
1312             int position = 0;
1313             for (int i = 0; i < candidates.Count; ++i)
1314             {
1315                 if ((candidates[i].ReturnType == tx) &&
1316                     (candidates[i].GetParameters()[0].ParameterType == sx) &&
1317                     (!(candidates[i] is LiftedConversionMethodInfo)))
1318                 {
1319                     position = i;
1320                     ++numMatches;
1321                 }
1322             }
1323             if (numMatches == 1)
1324             {
1325                 // found what we are looking for
1326                 error = null;
1327                 return candidates[position];
1328             }
1329 
1330             // now check for lifted conversions
1331             if ((toIsNullable) && (numMatches == 0))
1332             {
1333                 if (fromIsNullable)
1334                 {
1335                     for (int i = 0; i < candidates.Count; ++i)
1336                     {
1337                         if ((candidates[i].ReturnType == tx) &&
1338                             (candidates[i].GetParameters()[0].ParameterType == sx) &&
1339                             (candidates[i] is LiftedConversionMethodInfo))
1340                         {
1341                             position = i;
1342                             ++numMatches;
1343                         }
1344                     }
1345                     if (numMatches == 1)
1346                     {
1347                         // found what we are looking for
1348                         error = null;
1349                         return candidates[position];
1350                     }
1351                 }
1352                 else
1353                 {
1354                     // we are doing a conversion T? = S, so a conversion from S -> T is valid
1355                     MethodInfo result = FindImplicitConversion(fromType, toType0, out error);
1356                     if (result != null)
1357                     {
1358                         error = null;
1359                         // return it as a lifted method so the wrapping to T? is done
1360                         return new LiftedConversionMethodInfo(result);
1361                     }
1362                 }
1363             }
1364 
1365             // no exact matches, so it's an error
1366             string message2 = string.Format(CultureInfo.CurrentCulture,
1367                 Messages.AmbiguousConversion,
1368                 RuleDecompiler.DecompileType(fromType),
1369                 RuleDecompiler.DecompileType(toType));
1370             error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible);
1371             return null;
1372         }
1373 
1374         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
FindExplicitConversion(Type fromType, Type toType, out ValidationError error)1375         internal static MethodInfo FindExplicitConversion(Type fromType, Type toType, out ValidationError error)
1376         {
1377             List<MethodInfo> candidates = new List<MethodInfo>();
1378             ValidationError dummyError; // don't return transient errors
1379 
1380             bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
1381             bool toIsNullable = ConditionHelper.IsNullableValueType(toType);
1382             Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType;
1383             Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
1384 
1385             if (fromType0.IsClass)
1386             {
1387                 AddExplicitConversions(fromType0, fromType, toType, candidates);
1388                 Type baseType = fromType0.BaseType;
1389                 while ((baseType != null) && (baseType != typeof(object)))
1390                 {
1391                     AddExplicitConversions(baseType, fromType, toType, candidates);
1392                     baseType = baseType.BaseType;
1393                 }
1394             }
1395             else if (IsStruct(fromType0))
1396             {
1397                 AddExplicitConversions(fromType0, fromType, toType, candidates);
1398             }
1399             if (toType0.IsClass)
1400             {
1401                 AddExplicitConversions(toType0, fromType, toType, candidates);
1402                 Type baseType = toType0.BaseType;
1403                 while ((baseType != null) && (baseType != typeof(object)))
1404                 {
1405                     AddExplicitConversions(baseType, fromType, toType, candidates);
1406                     baseType = baseType.BaseType;
1407                 }
1408             }
1409             else if (IsStruct(toType0))
1410             {
1411                 AddExplicitConversions(toType0, fromType, toType, candidates);
1412             }
1413 
1414             // if both types are nullable, add the lifted operators
1415             if (fromIsNullable && toIsNullable)
1416             {
1417                 // start by finding all the conversion operators from S0 -> T0
1418                 List<MethodInfo> liftedCandidates = new List<MethodInfo>();
1419                 if (fromType0.IsClass)
1420                 {
1421                     AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
1422                     Type baseType = fromType0.BaseType;
1423                     while ((baseType != null) && (baseType != typeof(object)))
1424                     {
1425                         AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates);
1426                         baseType = baseType.BaseType;
1427                     }
1428                 }
1429                 else if (IsStruct(fromType0))
1430                 {
1431                     AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
1432                 }
1433                 if (toType0.IsClass)
1434                 {
1435                     AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates);
1436                     Type baseType = toType0.BaseType;
1437                     while ((baseType != null) && (baseType != typeof(object)))
1438                     {
1439                         AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates);
1440                         baseType = baseType.BaseType;
1441                     }
1442                 }
1443                 else if (IsStruct(toType0))
1444                 {
1445                     AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates);
1446                 }
1447 
1448                 // add them all to the candidates list as lifted methods (which wraps them appropriately)
1449                 foreach (MethodInfo mi in liftedCandidates)
1450                     candidates.Add(new LiftedConversionMethodInfo(mi));
1451             }
1452 
1453             if (candidates.Count == 0)
1454             {
1455                 // no overrides, so must be false
1456                 string message = string.Format(CultureInfo.CurrentCulture,
1457                     Messages.NoConversion,
1458                     RuleDecompiler.DecompileType(fromType),
1459                     RuleDecompiler.DecompileType(toType));
1460                 error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
1461                 return null;
1462             }
1463 
1464             // find the most specific source type
1465             // if any are s, s is the answer
1466             Type sx = null;
1467             for (int i = 0; i < candidates.Count; ++i)
1468             {
1469                 Type testType = candidates[i].GetParameters()[0].ParameterType;
1470                 if (testType == fromType)
1471                 {
1472                     // we have a match with the source type, so that's the correct answer
1473                     sx = fromType;
1474                     break;
1475                 }
1476             }
1477             // if no match, find the most encompassed type if the type encompasses s
1478             if (sx == null)
1479             {
1480                 for (int i = 0; i < candidates.Count; ++i)
1481                 {
1482                     Type testType = candidates[i].GetParameters()[0].ParameterType;
1483                     if (StandardImplicitConversion(fromType, testType, null, out dummyError))
1484                     {
1485                         if (sx == null)
1486                             sx = testType;
1487                         else if (StandardImplicitConversion(testType, sx, null, out dummyError))
1488                             sx = testType;
1489                     }
1490                 }
1491             }
1492             // still no match, find most encompassing type
1493             if (sx == null)
1494             {
1495                 for (int i = 0; i < candidates.Count; ++i)
1496                 {
1497                     Type testType = candidates[i].GetParameters()[0].ParameterType;
1498                     if (StandardImplicitConversion(testType, fromType, null, out dummyError))
1499                     {
1500                         if (sx == null)
1501                             sx = testType;
1502                         else if (StandardImplicitConversion(sx, testType, null, out dummyError))
1503                             sx = testType;
1504                     }
1505                 }
1506             }
1507 
1508             // find the most specific target type
1509             // if any are t, t is the answer
1510             Type tx = null;
1511             for (int i = 0; i < candidates.Count; ++i)
1512             {
1513                 Type testType = candidates[i].ReturnType;
1514                 if (testType == toType)
1515                 {
1516                     // we have a match with the target type, so that's the correct answer
1517                     tx = toType;
1518                     break;
1519                 }
1520             }
1521             // if no match, find the most encompassed type if the type encompasses s
1522             if (tx == null)
1523             {
1524                 for (int i = 0; i < candidates.Count; ++i)
1525                 {
1526                     Type testType = candidates[i].ReturnType;
1527                     if (StandardImplicitConversion(testType, toType, null, out dummyError))
1528                     {
1529                         if (tx == null)
1530                             tx = testType;
1531                         else if (StandardImplicitConversion(tx, testType, null, out dummyError))
1532                             tx = testType;
1533                     }
1534                 }
1535             }
1536             // still no match, find most encompassing type
1537             if (tx == null)
1538             {
1539                 for (int i = 0; i < candidates.Count; ++i)
1540                 {
1541                     Type testType = candidates[i].ReturnType;
1542                     if (StandardImplicitConversion(toType, testType, null, out dummyError))
1543                     {
1544                         if (tx == null)
1545                             tx = testType;
1546                         else if (StandardImplicitConversion(testType, tx, null, out dummyError))
1547                             tx = testType;
1548                     }
1549                 }
1550             }
1551 
1552             // see how many candidates convert from sx to tx, ignoring lifted methods
1553             int numMatches = 0;
1554             int position = 0;
1555             for (int i = 0; i < candidates.Count; ++i)
1556             {
1557                 if ((candidates[i].ReturnType == tx) &&
1558                         (candidates[i].GetParameters()[0].ParameterType == sx) &&
1559                         (!(candidates[i] is LiftedConversionMethodInfo)))
1560                 {
1561                     position = i;
1562                     ++numMatches;
1563                 }
1564             }
1565             if (numMatches == 1)
1566             {
1567                 // found what we are looking for
1568                 error = null;
1569                 return candidates[position];
1570             }
1571 
1572             // now check for lifted conversions
1573             if ((toIsNullable) && (numMatches == 0))
1574             {
1575                 if (fromIsNullable)
1576                 {
1577                     for (int i = 0; i < candidates.Count; ++i)
1578                     {
1579                         if ((candidates[i].ReturnType == tx) &&
1580                             (candidates[i].GetParameters()[0].ParameterType == sx) &&
1581                             (candidates[i] is LiftedConversionMethodInfo))
1582                         {
1583                             position = i;
1584                             ++numMatches;
1585                         }
1586                     }
1587                     if (numMatches == 1)
1588                     {
1589                         // found what we are looking for
1590                         error = null;
1591                         return candidates[position];
1592                     }
1593                 }
1594                 else
1595                 {
1596                     // we are doing a conversion T? = S, so a conversion from S -> T is valid
1597                     MethodInfo result = FindExplicitConversion(fromType, toType0, out error);
1598                     if (result != null)
1599                     {
1600                         error = null;
1601                         // return it as a lifted method so the wrapping to T? is done
1602                         return new LiftedConversionMethodInfo(result);
1603                     }
1604                 }
1605             }
1606 
1607             // no exact matches, so it's an error
1608             string message2 = string.Format(CultureInfo.CurrentCulture,
1609                 Messages.AmbiguousConversion,
1610                 RuleDecompiler.DecompileType(fromType),
1611                 RuleDecompiler.DecompileType(toType));
1612             error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible);
1613             return null;
1614         }
1615 
IsStruct(Type type)1616         private static bool IsStruct(Type type)
1617         {
1618             return ((type.IsValueType) && (!type.IsPrimitive));
1619         }
1620 
1621         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
IsExplicitNumericConversion(Type sourceType, Type testType)1622         private static bool IsExplicitNumericConversion(Type sourceType, Type testType)
1623         {
1624             // includes the implicit conversions as well
1625 
1626             // unwrap nullables
1627             TypeCode sourceTypeCode = (ConditionHelper.IsNullableValueType(sourceType))
1628                 ? Type.GetTypeCode(sourceType.GetGenericArguments()[0])
1629                 : Type.GetTypeCode(sourceType);
1630             TypeCode testTypeCode = (ConditionHelper.IsNullableValueType(testType))
1631                 ? Type.GetTypeCode(testType.GetGenericArguments()[0])
1632                 : Type.GetTypeCode(testType);
1633 
1634             switch (sourceTypeCode)
1635             {
1636                 case TypeCode.SByte:
1637                     switch (testTypeCode)
1638                     {
1639                         case TypeCode.SByte:
1640                         case TypeCode.Byte:
1641                         case TypeCode.UInt16:
1642                         case TypeCode.UInt32:
1643                         case TypeCode.UInt64:
1644                         case TypeCode.Char:
1645 
1646                         case TypeCode.Int16:
1647                         case TypeCode.Int32:
1648                         case TypeCode.Int64:
1649                         case TypeCode.Single:
1650                         case TypeCode.Double:
1651                         case TypeCode.Decimal:
1652                             return true;
1653                     }
1654                     return false;
1655 
1656                 case TypeCode.Byte:
1657                     switch (testTypeCode)
1658                     {
1659                         case TypeCode.Byte:
1660                         case TypeCode.SByte:
1661                         case TypeCode.Char:
1662 
1663                         case TypeCode.Int16:
1664                         case TypeCode.UInt16:
1665                         case TypeCode.Int32:
1666                         case TypeCode.UInt32:
1667                         case TypeCode.Int64:
1668                         case TypeCode.UInt64:
1669                         case TypeCode.Single:
1670                         case TypeCode.Double:
1671                         case TypeCode.Decimal:
1672                             return true;
1673                     }
1674                     return false;
1675 
1676                 case TypeCode.Int16:
1677                     switch (testTypeCode)
1678                     {
1679                         case TypeCode.SByte:
1680                         case TypeCode.Byte:
1681                         case TypeCode.UInt16:
1682                         case TypeCode.UInt32:
1683                         case TypeCode.UInt64:
1684                         case TypeCode.Char:
1685 
1686                         case TypeCode.Int16:
1687                         case TypeCode.Int32:
1688                         case TypeCode.Int64:
1689                         case TypeCode.Single:
1690                         case TypeCode.Double:
1691                         case TypeCode.Decimal:
1692                             return true;
1693                     }
1694                     return false;
1695 
1696                 case TypeCode.UInt16:
1697                     switch (testTypeCode)
1698                     {
1699                         case TypeCode.SByte:
1700                         case TypeCode.Byte:
1701                         case TypeCode.Int16:
1702                         case TypeCode.UInt16:
1703                         case TypeCode.Char:
1704 
1705                         case TypeCode.Int32:
1706                         case TypeCode.UInt32:
1707                         case TypeCode.Int64:
1708                         case TypeCode.UInt64:
1709                         case TypeCode.Single:
1710                         case TypeCode.Double:
1711                         case TypeCode.Decimal:
1712                             return true;
1713                     }
1714                     return false;
1715 
1716                 case TypeCode.Int32:
1717                     switch (testTypeCode)
1718                     {
1719                         case TypeCode.SByte:
1720                         case TypeCode.Byte:
1721                         case TypeCode.Int16:
1722                         case TypeCode.UInt16:
1723                         case TypeCode.Int32:
1724                         case TypeCode.UInt32:
1725                         case TypeCode.UInt64:
1726                         case TypeCode.Char:
1727 
1728                         case TypeCode.Int64:
1729                         case TypeCode.Single:
1730                         case TypeCode.Double:
1731                         case TypeCode.Decimal:
1732                             return true;
1733                     }
1734                     return false;
1735 
1736                 case TypeCode.UInt32:
1737                     switch (testTypeCode)
1738                     {
1739                         case TypeCode.SByte:
1740                         case TypeCode.Byte:
1741                         case TypeCode.Int16:
1742                         case TypeCode.UInt16:
1743                         case TypeCode.Int32:
1744                         case TypeCode.UInt32:
1745                         case TypeCode.Char:
1746 
1747                         case TypeCode.Int64:
1748                         case TypeCode.UInt64:
1749                         case TypeCode.Single:
1750                         case TypeCode.Double:
1751                         case TypeCode.Decimal:
1752                             return true;
1753                     }
1754                     return false;
1755 
1756                 case TypeCode.Int64:
1757                     switch (testTypeCode)
1758                     {
1759                         case TypeCode.SByte:
1760                         case TypeCode.Byte:
1761                         case TypeCode.Int16:
1762                         case TypeCode.UInt16:
1763                         case TypeCode.Int32:
1764                         case TypeCode.UInt32:
1765                         case TypeCode.Int64:
1766                         case TypeCode.UInt64:
1767                         case TypeCode.Char:
1768 
1769                         case TypeCode.Single:
1770                         case TypeCode.Double:
1771                         case TypeCode.Decimal:
1772                             return true;
1773                     }
1774                     return false;
1775 
1776                 case TypeCode.UInt64:
1777                     switch (testTypeCode)
1778                     {
1779                         case TypeCode.SByte:
1780                         case TypeCode.Byte:
1781                         case TypeCode.Int16:
1782                         case TypeCode.UInt16:
1783                         case TypeCode.Int32:
1784                         case TypeCode.UInt32:
1785                         case TypeCode.Int64:
1786                         case TypeCode.UInt64:
1787                         case TypeCode.Char:
1788 
1789                         case TypeCode.Single:
1790                         case TypeCode.Double:
1791                         case TypeCode.Decimal:
1792                             return true;
1793                     }
1794                     return false;
1795 
1796                 case TypeCode.Char:
1797                     switch (testTypeCode)
1798                     {
1799                         case TypeCode.Char:
1800                         case TypeCode.SByte:
1801                         case TypeCode.Byte:
1802                         case TypeCode.Int16:
1803 
1804                         case TypeCode.UInt16:
1805                         case TypeCode.Int32:
1806                         case TypeCode.UInt32:
1807                         case TypeCode.Int64:
1808                         case TypeCode.UInt64:
1809                         case TypeCode.Single:
1810                         case TypeCode.Double:
1811                         case TypeCode.Decimal:
1812                             return true;
1813                     }
1814                     return false;
1815 
1816                 case TypeCode.Single:
1817                     switch (testTypeCode)
1818                     {
1819                         case TypeCode.SByte:
1820                         case TypeCode.Byte:
1821                         case TypeCode.Int16:
1822                         case TypeCode.UInt16:
1823                         case TypeCode.Int32:
1824                         case TypeCode.UInt32:
1825                         case TypeCode.Int64:
1826                         case TypeCode.UInt64:
1827                         case TypeCode.Char:
1828                         case TypeCode.Single:
1829                         case TypeCode.Decimal:
1830 
1831                         case TypeCode.Double:
1832                             return true;
1833                     }
1834                     return false;
1835 
1836                 case TypeCode.Double:
1837                     switch (testTypeCode)
1838                     {
1839                         case TypeCode.SByte:
1840                         case TypeCode.Byte:
1841                         case TypeCode.Int16:
1842                         case TypeCode.UInt16:
1843                         case TypeCode.Int32:
1844                         case TypeCode.UInt32:
1845                         case TypeCode.Int64:
1846                         case TypeCode.UInt64:
1847                         case TypeCode.Char:
1848                         case TypeCode.Single:
1849                         case TypeCode.Double:
1850                         case TypeCode.Decimal:
1851                             return true;
1852                     }
1853                     return false;
1854 
1855                 case TypeCode.Decimal:
1856                     switch (testTypeCode)
1857                     {
1858                         case TypeCode.SByte:
1859                         case TypeCode.Byte:
1860                         case TypeCode.Int16:
1861                         case TypeCode.UInt16:
1862                         case TypeCode.Int32:
1863                         case TypeCode.UInt32:
1864                         case TypeCode.Int64:
1865                         case TypeCode.UInt64:
1866                         case TypeCode.Char:
1867                         case TypeCode.Single:
1868                         case TypeCode.Double:
1869                         case TypeCode.Decimal:
1870                             return true;
1871                     }
1872                     return false;
1873             }
1874             return false;
1875         }
1876 
1877 
ImplicitConversion(Type fromType, Type toType)1878         internal static bool ImplicitConversion(Type fromType, Type toType)
1879         {
1880             ValidationError error;
1881 
1882             // is there a standard conversion we can use
1883             if (StandardImplicitConversion(fromType, toType, null, out error))
1884                 return true;
1885 
1886             // no standard one, did the user provide one?
1887             return (FindImplicitConversion(fromType, toType, out error) != null);
1888         }
1889 
1890         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
StandardImplicitConversion(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)1891         internal static bool StandardImplicitConversion(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)
1892         {
1893             error = null;
1894 
1895             // 6.1.1 identity conversion
1896             if (rhsType == lhsType)
1897             {
1898                 // Easy special case... they're the same type.
1899                 return true;
1900             }
1901 
1902             // 6.1.4 (h) from the null type to any reference-type
1903             if (rhsType == typeof(NullLiteral))
1904             {
1905                 // Special case if the RHS is 'null'; just make sure the LHS type can be assigned a null value.
1906                 if (ConditionHelper.IsNonNullableValueType(lhsType))
1907                 {
1908                     string message = string.Format(CultureInfo.CurrentCulture, Messages.AssignNotAllowed, Messages.NullValue, RuleDecompiler.DecompileType(lhsType));
1909                     error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
1910                     return false;
1911                 }
1912                 return true;
1913             }
1914 
1915             // check for nullables
1916             bool lhsIsNullable = ConditionHelper.IsNullableValueType(lhsType);
1917             bool rhsIsNullable = ConditionHelper.IsNullableValueType(rhsType);
1918             if (rhsIsNullable)
1919             {
1920                 if (!lhsIsNullable)
1921                 {
1922                     // We had T1 = T2?, which is not valid for any T1 or T2, unless T1 is object
1923                     return (lhsType == typeof(object));
1924                 }
1925 
1926                 rhsType = Nullable.GetUnderlyingType(rhsType);
1927             }
1928 
1929             if (lhsIsNullable)
1930                 lhsType = Nullable.GetUnderlyingType(lhsType);
1931 
1932             if (lhsType == rhsType)
1933             {
1934                 // We had T? = T, which is valid.
1935                 return true;
1936             }
1937 
1938             // handle rest of 6.1.4
1939             if (TypeProvider.IsAssignable(lhsType, rhsType))
1940             {
1941                 // They are assignable, which will handle inheritance and trivial up-casting.
1942                 return true;
1943             }
1944 
1945             // 6.1.3 implicit enumeration conversions
1946             if (lhsType.IsEnum)
1947             {
1948                 // right-hand side can be decimal-integer-literal 0
1949                 CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression;
1950                 if ((primitive == null) || (primitive.Value == null))
1951                 {
1952                     // not a constant
1953                     return false;
1954                 }
1955                 switch (Type.GetTypeCode(primitive.Value.GetType()))
1956                 {
1957                     case TypeCode.SByte:
1958                         return ((sbyte)primitive.Value == 0);
1959                     case TypeCode.Byte:
1960                         return ((byte)primitive.Value == 0);
1961                     case TypeCode.Int16:
1962                         return ((short)primitive.Value == 0);
1963                     case TypeCode.UInt16:
1964                         return ((ushort)primitive.Value == 0);
1965                     case TypeCode.Int32:
1966                         return ((int)primitive.Value == 0);
1967                     case TypeCode.UInt32:
1968                         return ((uint)primitive.Value == 0);
1969                     case TypeCode.Int64:
1970                         return ((long)primitive.Value == 0);
1971                     case TypeCode.UInt64:
1972                         return ((ulong)primitive.Value == 0);
1973                     case TypeCode.Char:
1974                         return ((char)primitive.Value == 0);
1975                 }
1976                 return false;
1977             }
1978             if (rhsType.IsEnum)
1979             {
1980                 // don't treat enums as numbers
1981                 return false;
1982             }
1983 
1984             // 6.1.2 implicit numeric conversions
1985             // 6.1.6 implicit constant expression conversions
1986             // not assignable, but the assignment might still be valid for
1987             // value types if a free conversion is available.
1988             TypeCode lhsTypeCode = Type.GetTypeCode(lhsType);
1989             TypeCode rhsTypeCode = Type.GetTypeCode(rhsType);
1990 
1991             switch (lhsTypeCode)
1992             {
1993                 case TypeCode.Decimal:
1994                     switch (rhsTypeCode)
1995                     {
1996                         case TypeCode.SByte:
1997                         case TypeCode.Byte:
1998                         case TypeCode.Int16:
1999                         case TypeCode.UInt16:
2000                         case TypeCode.Int32:
2001                         case TypeCode.UInt32:
2002                         case TypeCode.Int64:
2003                         case TypeCode.UInt64:
2004                         case TypeCode.Decimal:
2005                         case TypeCode.Char:
2006                             return true;
2007                     }
2008                     return false;
2009 
2010                 case TypeCode.Double:
2011                     switch (rhsTypeCode)
2012                     {
2013                         case TypeCode.SByte:
2014                         case TypeCode.Byte:
2015                         case TypeCode.Int16:
2016                         case TypeCode.UInt16:
2017                         case TypeCode.Int32:
2018                         case TypeCode.UInt32:
2019                         case TypeCode.Int64:
2020                         case TypeCode.UInt64:
2021                         case TypeCode.Single:
2022                         case TypeCode.Double:
2023                         case TypeCode.Char:
2024                             return true;
2025                     }
2026                     return false;
2027 
2028                 case TypeCode.Single:
2029                     switch (rhsTypeCode)
2030                     {
2031                         case TypeCode.SByte:
2032                         case TypeCode.Byte:
2033                         case TypeCode.Int16:
2034                         case TypeCode.UInt16:
2035                         case TypeCode.Int32:
2036                         case TypeCode.UInt32:
2037                         case TypeCode.Int64:
2038                         case TypeCode.UInt64:
2039                         case TypeCode.Single:
2040                         case TypeCode.Char:
2041                             return true;
2042                     }
2043                     return false;
2044 
2045                 case TypeCode.Char:
2046                     switch (rhsTypeCode)
2047                     {
2048                         case TypeCode.Char:
2049                             return true;
2050                         case TypeCode.SByte:
2051                         case TypeCode.Byte:
2052                         case TypeCode.Int16:
2053                         case TypeCode.UInt16:
2054                         case TypeCode.Int32:
2055                         case TypeCode.UInt32:
2056                         case TypeCode.Int64:
2057                         case TypeCode.UInt64:
2058                             // Maybe, if the value is in range.
2059                             return CheckValueRange(rhsExpression, lhsType, out error);
2060                     }
2061                     return false;
2062 
2063                 case TypeCode.SByte:
2064                     switch (rhsTypeCode)
2065                     {
2066                         case TypeCode.SByte:
2067                             return true;
2068                         case TypeCode.Byte:
2069                         case TypeCode.Int16:
2070                         case TypeCode.UInt16:
2071                         case TypeCode.Int32:
2072                         case TypeCode.UInt32:
2073                         case TypeCode.Int64:
2074                         case TypeCode.UInt64:
2075                         case TypeCode.Char:
2076                             // Maybe, if the value is in range.
2077                             return CheckValueRange(rhsExpression, lhsType, out error);
2078                     }
2079                     return false;
2080 
2081                 case TypeCode.Byte:
2082                     switch (rhsTypeCode)
2083                     {
2084                         case TypeCode.Byte:
2085                             return true;
2086                         case TypeCode.SByte:
2087                         case TypeCode.Int16:
2088                         case TypeCode.UInt16:
2089                         case TypeCode.Int32:
2090                         case TypeCode.UInt32:
2091                         case TypeCode.Int64:
2092                         case TypeCode.UInt64:
2093                         case TypeCode.Char:
2094                             // Maybe, if the value is in range.
2095                             return CheckValueRange(rhsExpression, lhsType, out error);
2096                     }
2097                     return false;
2098 
2099                 case TypeCode.Int16:
2100                     switch (rhsTypeCode)
2101                     {
2102                         case TypeCode.SByte:
2103                         case TypeCode.Byte:
2104                         case TypeCode.Int16:
2105                             return true;
2106                         case TypeCode.UInt16:
2107                         case TypeCode.Int32:
2108                         case TypeCode.UInt32:
2109                         case TypeCode.Int64:
2110                         case TypeCode.UInt64:
2111                         case TypeCode.Char:
2112                             // Maybe, if the value is in range.
2113                             return CheckValueRange(rhsExpression, lhsType, out error);
2114                     }
2115                     return false;
2116 
2117                 case TypeCode.Int32:
2118                     switch (rhsTypeCode)
2119                     {
2120                         case TypeCode.SByte:
2121                         case TypeCode.Byte:
2122                         case TypeCode.Int16:
2123                         case TypeCode.UInt16:
2124                         case TypeCode.Int32:
2125                         case TypeCode.Char:
2126                             return true;
2127                         case TypeCode.UInt32:
2128                         case TypeCode.Int64:
2129                         case TypeCode.UInt64:
2130                             // Maybe, if the value is in range.
2131                             return CheckValueRange(rhsExpression, lhsType, out error);
2132                     }
2133                     return false;
2134 
2135                 case TypeCode.Int64:
2136                     switch (rhsTypeCode)
2137                     {
2138                         case TypeCode.SByte:
2139                         case TypeCode.Byte:
2140                         case TypeCode.Int16:
2141                         case TypeCode.UInt16:
2142                         case TypeCode.Int32:
2143                         case TypeCode.UInt32:
2144                         case TypeCode.Int64:
2145                         case TypeCode.Char:
2146                             return true;
2147                         case TypeCode.UInt64:
2148                             // Maybe, if the value is in range.
2149                             return CheckValueRange(rhsExpression, lhsType, out error);
2150                     }
2151                     return false;
2152 
2153                 case TypeCode.UInt16:
2154                     switch (rhsTypeCode)
2155                     {
2156                         case TypeCode.Byte:
2157                         case TypeCode.UInt16:
2158                         case TypeCode.Char:
2159                             return true;
2160                         case TypeCode.SByte:
2161                         case TypeCode.Int16:
2162                         case TypeCode.Int32:
2163                         case TypeCode.UInt32:
2164                         case TypeCode.Int64:
2165                         case TypeCode.UInt64:
2166                             // Maybe, if the value is in range.
2167                             return CheckValueRange(rhsExpression, lhsType, out error);
2168                     }
2169                     return false;
2170 
2171                 case TypeCode.UInt32:
2172                     switch (rhsTypeCode)
2173                     {
2174                         case TypeCode.Byte:
2175                         case TypeCode.UInt16:
2176                         case TypeCode.UInt32:
2177                         case TypeCode.Char:
2178                             return true;
2179                         case TypeCode.SByte:
2180                         case TypeCode.Int16:
2181                         case TypeCode.Int32:
2182                         case TypeCode.Int64:
2183                         case TypeCode.UInt64:
2184                             // Maybe, if the value is in range.
2185                             return CheckValueRange(rhsExpression, lhsType, out error);
2186                     }
2187                     return false;
2188 
2189                 case TypeCode.UInt64:
2190                     switch (rhsTypeCode)
2191                     {
2192                         case TypeCode.Byte:
2193                         case TypeCode.UInt16:
2194                         case TypeCode.UInt32:
2195                         case TypeCode.UInt64:
2196                         case TypeCode.Char:
2197                             return true;
2198                         case TypeCode.SByte:
2199                         case TypeCode.Int16:
2200                         case TypeCode.Int32:
2201                         case TypeCode.Int64:
2202                             // Maybe, if the value is in range.
2203                             return CheckValueRange(rhsExpression, lhsType, out error);
2204                     }
2205                     return false;
2206 
2207                 default:
2208                     // It wasn't a numeric type, it was some other kind of value type (e.g., bool,
2209                     // DateTime, etc).  There will be no conversions.
2210                     return false;
2211             }
2212         }
2213 
AddImplicitConversions(Type t, Type source, Type target, List<MethodInfo> methods)2214         private static void AddImplicitConversions(Type t, Type source, Type target, List<MethodInfo> methods)
2215         {
2216             // append the list of methods that match the name specified
2217             // s is the source type, so the parameter must encompass it
2218             // t is the target type, so it must encompass the result
2219             MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public);
2220             foreach (MethodInfo mi in possible)
2221             {
2222                 if ((mi.Name == "op_Implicit") && (mi.GetParameters().Length == 1))
2223                 {
2224                     Type sourceType = mi.GetParameters()[0].ParameterType;
2225                     Type targetType = mi.ReturnType;
2226                     ValidationError error;
2227                     if (StandardImplicitConversion(source, sourceType, null, out error) &&
2228                         StandardImplicitConversion(targetType, target, null, out error))
2229                     {
2230                         if (!methods.Contains(mi))
2231                             methods.Add(mi);
2232                     }
2233                 }
2234             }
2235         }
2236 
AddExplicitConversions(Type t, Type source, Type target, List<MethodInfo> methods)2237         private static void AddExplicitConversions(Type t, Type source, Type target, List<MethodInfo> methods)
2238         {
2239             // append the list of methods that match the name specified
2240             // s is the source type, so the parameter must encompass it
2241             // t is the target type, so it must encompass the result
2242             MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public);
2243             foreach (MethodInfo mi in possible)
2244             {
2245                 if (((mi.Name == "op_Implicit") || (mi.Name == "op_Explicit")) && (mi.GetParameters().Length == 1))
2246                 {
2247                     Type sourceType = mi.GetParameters()[0].ParameterType;
2248                     Type targetType = mi.ReturnType;
2249                     ValidationError error;
2250                     if ((StandardImplicitConversion(source, sourceType, null, out error) || StandardImplicitConversion(sourceType, source, null, out error))
2251                      && (StandardImplicitConversion(target, targetType, null, out error) || StandardImplicitConversion(targetType, target, null, out error)))
2252                     {
2253                         if (!methods.Contains(mi))
2254                             methods.Add(mi);
2255                     }
2256                 }
2257             }
2258         }
2259 
2260         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
CheckValueRange(CodeExpression rhsExpression, Type lhsType, out ValidationError error)2261         private static bool CheckValueRange(CodeExpression rhsExpression, Type lhsType, out ValidationError error)
2262         {
2263             error = null;
2264 
2265             CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression;
2266             if (primitive != null)
2267             {
2268                 try
2269                 {
2270                     System.Convert.ChangeType(primitive.Value, lhsType, CultureInfo.CurrentCulture);
2271                     // If we get here without throwing, it's valid.
2272                     return true;
2273                 }
2274                 catch (Exception e)
2275                 {
2276                     error = new ValidationError(e.Message, ErrorNumbers.Error_OperandTypesIncompatible);
2277                     return false;
2278                 }
2279             }
2280 
2281             return false;
2282         }
2283 
ValidateMemberAccess( CodeExpression targetExpression, Type targetType, FieldInfo accessorMethod, string memberName, CodeExpression parentExpr)2284         internal bool ValidateMemberAccess(
2285             CodeExpression targetExpression, Type targetType, FieldInfo accessorMethod, string memberName, CodeExpression parentExpr)
2286         {
2287             return this.ValidateMemberAccess(
2288                 targetExpression, targetType, memberName, parentExpr,
2289                 accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
2290         }
2291 
ValidateMemberAccess( CodeExpression targetExpression, Type targetType, MethodInfo accessorMethod, string memberName, CodeExpression parentExpr)2292         internal bool ValidateMemberAccess(
2293             CodeExpression targetExpression, Type targetType, MethodInfo accessorMethod, string memberName, CodeExpression parentExpr)
2294         {
2295             return this.ValidateMemberAccess(
2296                 targetExpression, targetType, memberName, parentExpr,
2297                 accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
2298         }
2299 
ValidateMemberAccess( CodeExpression targetExpression, Type targetType, string memberName, CodeExpression parentExpr, Assembly methodAssembly, bool isPrivate, bool isInternal, bool isStatic)2300         private bool ValidateMemberAccess(
2301             CodeExpression targetExpression, Type targetType, string memberName, CodeExpression parentExpr,
2302             Assembly methodAssembly, bool isPrivate, bool isInternal, bool isStatic)
2303         {
2304             string message;
2305 
2306             if (isStatic != (targetExpression is CodeTypeReferenceExpression))
2307             {
2308                 // If it's static, then the target object must be a type ref, and vice versa.
2309 
2310                 int errorNumber;
2311 
2312                 if (isStatic)
2313                 {
2314                     // We have "object.StaticMember"
2315                     message = string.Format(CultureInfo.CurrentCulture, Messages.StaticMember, memberName);
2316                     errorNumber = ErrorNumbers.Error_StaticMember;
2317                 }
2318                 else
2319                 {
2320                     // We have "TypeName.NonStaticMember"
2321                     message = string.Format(CultureInfo.CurrentCulture, Messages.NonStaticMember, memberName);
2322                     errorNumber = ErrorNumbers.Error_NonStaticMember;
2323                 }
2324 
2325                 ValidationError error = new ValidationError(message, errorNumber);
2326                 error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
2327                 Errors.Add(error);
2328 
2329                 return false;
2330             }
2331 
2332             if (isPrivate && targetType != ThisType)
2333             {
2334                 // Can't access private members except on the subject type.
2335                 message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessPrivateMember, memberName, RuleDecompiler.DecompileType(targetType));
2336                 ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
2337                 error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
2338                 Errors.Add(error);
2339 
2340                 return false;
2341             }
2342 
2343             if (isInternal && ThisType.Assembly != methodAssembly)
2344             {
2345                 // Can't access internal members except on the subject assembly.
2346                 message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessInternalMember, memberName, RuleDecompiler.DecompileType(targetType));
2347                 ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
2348                 error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
2349                 Errors.Add(error);
2350 
2351                 return false;
2352             }
2353 
2354             return true;
2355         }
2356 
2357         #region Field and property resolution
2358 
ResolveFieldOrProperty(Type targetType, string name)2359         internal MemberInfo ResolveFieldOrProperty(Type targetType, string name)
2360         {
2361             BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
2362             if (AllowInternalMembers(targetType))
2363                 bindingFlags |= BindingFlags.NonPublic;
2364 
2365             // Look up a field or property of the given name.
2366             MemberInfo[] results = targetType.GetMember(name, MemberTypes.Field | MemberTypes.Property, bindingFlags);
2367 
2368             if (results != null)
2369             {
2370                 int numResults = results.Length;
2371                 if (numResults == 1)
2372                 {
2373                     // If we found exactly one, we're good.
2374                     return results[0];
2375                 }
2376                 else if (numResults > 1)
2377                 {
2378                     // We may have found more than one property if it's overloaded.  If we find one without
2379                     // any parameters, return that one.
2380                     for (int i = 0; i < numResults; ++i)
2381                     {
2382                         MemberInfo member = results[i];
2383                         System.Diagnostics.Debug.Assert(member.MemberType == MemberTypes.Property, "only properties can be overloaded");
2384 
2385                         PropertyInfo pi = (PropertyInfo)member;
2386                         ParameterInfo[] parms = pi.GetIndexParameters();
2387                         if (parms == null || parms.Length == 0)
2388                         {
2389                             if (pi != null)
2390                             {
2391                                 IsAuthorized(pi.PropertyType);
2392                             }
2393                             return pi;
2394                         }
2395                     }
2396                 }
2397             }
2398 
2399             // If we didn't find it, and if the target type is an interface, try resolving a property
2400             // that may exist in its inheritance chain.  (Fields cannot appear on interfaces.)
2401             if (targetType.IsInterface)
2402                 return ResolveProperty(targetType, name, bindingFlags);
2403 
2404             // Otherwise, it's no good.
2405             return null;
2406         }
2407 
ResolveProperty(Type targetType, string propertyName, BindingFlags bindingFlags)2408         internal PropertyInfo ResolveProperty(Type targetType, string propertyName, BindingFlags bindingFlags)
2409         {
2410 
2411             PropertyInfo pi = GetProperty(targetType, propertyName, bindingFlags);
2412             if (pi == null && targetType.IsInterface)
2413             {
2414                 Type[] parentInterfacesArray = targetType.GetInterfaces();
2415                 List<Type> parentInterfaces = new List<Type>();
2416                 parentInterfaces.AddRange(parentInterfacesArray);
2417 
2418                 int index = 0;
2419                 while (index < parentInterfaces.Count)
2420                 {
2421                     pi = GetProperty(parentInterfaces[index], propertyName, bindingFlags);
2422                     if (pi != null)
2423                         break;
2424 
2425                     Type[] pInterfaces = parentInterfaces[index].GetInterfaces();
2426                     if (pInterfaces.Length > 0)
2427                         parentInterfaces.AddRange(pInterfaces);
2428                     ++index;
2429                 }
2430             }
2431 
2432             if (pi != null)
2433             {
2434                 IsAuthorized(pi.PropertyType);
2435             }
2436             return pi;
2437         }
2438 
GetProperty(Type targetType, string propertyName, BindingFlags bindingFlags)2439         private static PropertyInfo GetProperty(Type targetType, string propertyName, BindingFlags bindingFlags)
2440         {
2441             // Properties may be overloaded (in VB), so we have to ---- out those that we can support,
2442             // i.e., those that have no parameters.
2443 
2444             MemberInfo[] members = targetType.GetMember(propertyName, MemberTypes.Property, bindingFlags);
2445             for (int m = 0; m < members.Length; ++m)
2446             {
2447                 PropertyInfo pi = (PropertyInfo)members[m];
2448 
2449                 ParameterInfo[] parms = pi.GetIndexParameters();
2450                 if (parms == null || parms.Length == 0)
2451                     return pi;
2452             }
2453 
2454             return null;
2455         }
2456 
2457         #endregion
2458 
2459         #region Method resolution
2460 
2461         private class Argument
2462         {
2463             internal CodeExpression expression;
2464             internal FieldDirection direction;
2465             internal Type type;
2466 
Argument(CodeExpression expr, RuleValidation validation)2467             internal Argument(CodeExpression expr, RuleValidation validation)
2468             {
2469                 this.expression = expr;
2470 
2471                 this.direction = FieldDirection.In;
2472                 CodeDirectionExpression directionExpr = expr as CodeDirectionExpression;
2473                 if (directionExpr != null)
2474                     this.direction = directionExpr.Direction;
2475 
2476                 this.type = validation.ExpressionInfo(expr).ExpressionType;
2477             }
2478 
Argument(Type type)2479             internal Argument(Type type)
2480             {
2481                 this.direction = FieldDirection.In;
2482                 this.type = type;
2483             }
2484         }
2485 
2486         private class CandidateParameter
2487         {
2488             private Type type;
2489             private FieldDirection direction;
2490 
CandidateParameter(Type type)2491             internal CandidateParameter(Type type)
2492             {
2493                 this.type = type;
2494                 this.direction = FieldDirection.In;
2495             }
2496 
CandidateParameter(ParameterInfo paramInfo)2497             internal CandidateParameter(ParameterInfo paramInfo)
2498             {
2499                 this.direction = FieldDirection.In;
2500                 if (paramInfo.IsOut)
2501                     this.direction = FieldDirection.Out;
2502                 else if (paramInfo.ParameterType.IsByRef)
2503                     this.direction = FieldDirection.Ref;
2504 
2505                 this.type = paramInfo.ParameterType;
2506             }
2507 
Match(Argument argument, string methodName, int argPosition, out ValidationError error)2508             internal bool Match(Argument argument, string methodName, int argPosition, out ValidationError error)
2509             {
2510                 string message;
2511 
2512                 // If we don't agree on the argument direction, this method is not a candidate.
2513                 if (this.direction != argument.direction)
2514                 {
2515                     string dirString = "";
2516                     switch (this.direction)
2517                     {
2518                         case FieldDirection.In:
2519                             dirString = "in"; // No localization required, this is a keyword.
2520                             break;
2521                         case FieldDirection.Out:
2522                             dirString = "out"; // No localization required, this is a keyword.
2523                             break;
2524                         case FieldDirection.Ref:
2525                             dirString = "ref"; // No localization required, this is a keyword.
2526                             break;
2527                     }
2528 
2529                     message = string.Format(CultureInfo.CurrentCulture, Messages.MethodDirectionMismatch, argPosition, methodName, dirString);
2530                     error = new ValidationError(message, ErrorNumbers.Error_MethodDirectionMismatch);
2531 
2532                     return false;
2533                 }
2534 
2535                 if (this.type.IsByRef && this.type != argument.type)
2536                 {
2537                     // If the parameter is "ref" or "out", then the types must match exactly.
2538                     // If not, this method can't be a candidate.
2539 
2540                     message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type));
2541                     error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);
2542 
2543                     return false;
2544                 }
2545 
2546                 // If the argument type is not assignable to the corresponding parameter type,
2547                 // this method can't be a candidate.
2548                 if (!RuleValidation.TypesAreAssignable(argument.type, this.type, argument.expression, out error))
2549                 {
2550                     if (error == null)
2551                     {
2552                         message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type));
2553                         error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);
2554                     }
2555                     return false;
2556                 }
2557 
2558                 // If we passed the above checks, this argument is a candidate match for the parameter.
2559                 return true;
2560             }
2561 
Equals(object obj)2562             public override bool Equals(object obj)
2563             {
2564                 CandidateParameter otherParam = obj as CandidateParameter;
2565                 if (otherParam == null)
2566                     return false;
2567 
2568                 return this.direction == otherParam.direction && this.type == otherParam.type;
2569             }
2570 
GetHashCode()2571             public override int GetHashCode()
2572             {
2573                 return this.direction.GetHashCode() ^ this.type.GetHashCode();
2574             }
2575 
CompareConversion(CandidateParameter otherParam, Argument argument)2576             internal int CompareConversion(CandidateParameter otherParam, Argument argument)
2577             {
2578                 // Return 0 if they are equal; 1 if this is better; -1 if this is worse.
2579                 // This follows the C# specification 7.4.2.3
2580                 int better = 1;
2581                 int worse = -1;
2582                 int equal = 0;
2583 
2584                 // If the two candidate parameters have the same type, neither one is better.
2585                 if (this.type == otherParam.type)
2586                     return equal;
2587 
2588                 // If the argument type is the same as one of the parameter types, that parameter is better.
2589                 if (argument.type == this.type)
2590                     return better;
2591                 if (argument.type == otherParam.type)
2592                     return worse;
2593 
2594                 // If this parameter can be converted to the other parameter, and not vice versa, then
2595                 // this is a better conversion.  (And in the reverse situation, it's a worse conversion.)
2596                 ValidationError dummy;
2597                 bool thisConvertsToOther = RuleValidation.TypesAreAssignable(this.type, otherParam.type, null, out dummy);
2598                 bool otherConvertsToThis = RuleValidation.TypesAreAssignable(otherParam.type, this.type, null, out dummy);
2599                 if (thisConvertsToOther && !otherConvertsToThis)
2600                     return better;
2601                 if (otherConvertsToThis && !thisConvertsToOther)
2602                     return worse;
2603 
2604                 // See if one is a better sign-preserving conversion than the other.
2605                 if (BetterSignedConversion(this.type, otherParam.type))
2606                     return better;
2607                 if (BetterSignedConversion(otherParam.type, this.type))
2608                     return worse;
2609 
2610                 // Otherwise, neither conversion is better.
2611                 return equal;
2612             }
2613 
2614             [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
BetterSignedConversion(Type t1, Type t2)2615             private static bool BetterSignedConversion(Type t1, Type t2)
2616             {
2617                 TypeCode tc1 = Type.GetTypeCode(t1);
2618                 TypeCode tc2 = Type.GetTypeCode(t2);
2619 
2620                 switch (tc1)
2621                 {
2622                     case TypeCode.SByte:
2623                         switch (tc2)
2624                         {
2625                             case TypeCode.Byte:
2626                             case TypeCode.UInt16:
2627                             case TypeCode.UInt32:
2628                             case TypeCode.UInt64:
2629                                 // A conversion to sbyte is better than a conversion to an unsigned type.
2630                                 return true;
2631                         }
2632                         break;
2633 
2634                     case TypeCode.Int16:
2635                         switch (tc2)
2636                         {
2637                             case TypeCode.UInt16:
2638                             case TypeCode.UInt32:
2639                             case TypeCode.UInt64:
2640                                 // A conversion to short is better than a conversion to an unsigned type.
2641                                 return true;
2642                         }
2643                         break;
2644 
2645                     case TypeCode.Int32:
2646                         if (tc2 == TypeCode.UInt32 || tc2 == TypeCode.UInt64)
2647                         {
2648                             // A conversion to int is better than a conversion to an unsigned type.
2649                             return true;
2650                         }
2651                         break;
2652 
2653                     case TypeCode.Int64:
2654                         if (tc2 == TypeCode.UInt64)
2655                         {
2656                             // A conversion to long is better than a conversion to an unsigned type.
2657                             return true;
2658                         }
2659                         break;
2660 
2661                     case TypeCode.Object:
2662                         // it is possible that the types are nullable
2663                         if (ConditionHelper.IsNullableValueType(t1))
2664                         {
2665                             t1 = t1.GetGenericArguments()[0];
2666                             // t2 may already be a value type
2667                             if (ConditionHelper.IsNullableValueType(t2))
2668                                 t2 = t2.GetGenericArguments()[0];
2669                             return BetterSignedConversion(t1, t2);
2670                         }
2671                         return false;
2672                 }
2673 
2674                 return false;
2675             }
2676         }
2677 
2678         private class CandidateMember
2679         {
2680             internal enum Form
2681             {
2682                 Normal,     // no "params" expansion
2683                 Expanded    // matched only after "params" expansion
2684             }
2685 
2686             internal MemberInfo Member;
2687             private ParameterInfo[] memberParameters;
2688             private List<CandidateParameter> signature;
2689             private Form form;
2690             private static ParameterInfo[] noParameters = new ParameterInfo[0];
2691             private static List<CandidateParameter> noSignature = new List<CandidateParameter>();
2692 
2693             // Constructor for candidate methods with parameters.
CandidateMember(MemberInfo member, ParameterInfo[] parameters, List<CandidateParameter> signature, Form form)2694             internal CandidateMember(MemberInfo member, ParameterInfo[] parameters, List<CandidateParameter> signature, Form form)
2695             {
2696                 this.Member = member;
2697                 this.memberParameters = parameters;
2698                 this.signature = signature;
2699                 this.form = form;
2700             }
2701 
2702             // Constructor for a candidate method that has no parameters.
CandidateMember(MemberInfo member)2703             internal CandidateMember(MemberInfo member)
2704                 : this(member, noParameters, noSignature, Form.Normal)
2705             {
2706             }
2707 
2708             internal bool IsExpanded
2709             {
2710                 get { return form == Form.Expanded; }
2711             }
2712 
2713             [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
CompareMember(Type targetType, CandidateMember other, List<Argument> arguments, RuleValidation validator)2714             internal int CompareMember(Type targetType, CandidateMember other, List<Argument> arguments, RuleValidation validator)
2715             {
2716                 int better = 1;
2717                 int worse = -1;
2718                 int equal = 0;
2719 
2720                 // Methods in a base class are not candidates if any method in a derived class
2721                 // is applicable.
2722                 Type thisDeclaringType = this.Member.DeclaringType;
2723                 Type otherDeclaringType = other.Member.DeclaringType;
2724                 if (thisDeclaringType != otherDeclaringType)
2725                 {
2726                     if (TypeProvider.IsAssignable(otherDeclaringType, thisDeclaringType))
2727                     {
2728                         // This declaring type can be converted to the other declaring type,
2729                         // which means this one is more derived.
2730                         return better;
2731                     }
2732                     else if (TypeProvider.IsAssignable(thisDeclaringType, otherDeclaringType))
2733                     {
2734                         // The other declaring type can be converted to this declaring type,
2735                         // which means the other one is more derived.
2736                         return worse;
2737                     }
2738                 }
2739 
2740                 System.Diagnostics.Debug.Assert(arguments.Count == this.signature.Count);
2741                 System.Diagnostics.Debug.Assert(arguments.Count == other.signature.Count);
2742 
2743                 bool hasAtLeastOneBetterConversion = false;
2744                 bool hasAtLeastOneWorseConversion = false;
2745                 bool signaturesAreIdentical = true;
2746 
2747                 // pick non-extension methods over extension methods
2748                 // if both are extension methods, then pick the one in the namespace closest to "this"
2749                 ExtensionMethodInfo thisExtension = this.Member as ExtensionMethodInfo;
2750                 ExtensionMethodInfo otherExtension = other.Member as ExtensionMethodInfo;
2751                 if ((thisExtension == null) && (otherExtension != null))
2752                     return better;
2753                 else if ((thisExtension != null) && (otherExtension == null))
2754                     return worse;
2755                 else if ((thisExtension != null) && (otherExtension != null))
2756                 {
2757                     // we have 2 extension methods, which one is better
2758                     string[] thisNameSpace = thisExtension.DeclaringType.FullName.Split('.');
2759                     string[] otherNameSpace = otherExtension.DeclaringType.FullName.Split('.');
2760                     string[] bestNameSpace = validator.thisType.FullName.Split('.');
2761                     int thisMatch = MatchNameSpace(thisNameSpace, bestNameSpace);
2762                     int otherMatch = MatchNameSpace(otherNameSpace, bestNameSpace);
2763                     if (thisMatch > otherMatch)
2764                         return better;
2765                     else if (thisMatch < otherMatch)
2766                         return worse;
2767 
2768                     // compare arguments, including the "this" argument
2769                     CandidateParameter thisDeclaringParam = new CandidateParameter(thisExtension.AssumedDeclaringType);
2770                     CandidateParameter otherDeclaringParam = new CandidateParameter(otherExtension.AssumedDeclaringType);
2771                     if (!thisDeclaringParam.Equals(otherDeclaringParam))
2772                     {
2773                         signaturesAreIdentical = false;
2774                         int conversionResult = thisDeclaringParam.CompareConversion(otherDeclaringParam, new Argument(targetType));
2775                         if (conversionResult < 0)
2776                         {
2777                             // A conversion was found that was worse, so this candidate is not better.
2778                             hasAtLeastOneWorseConversion = true;
2779                         }
2780                         else if (conversionResult > 0)
2781                         {
2782                             // This candidate had at least one conversion that was better.  (But
2783                             // we have to keep looking in case there's one that's worse.)
2784                             hasAtLeastOneBetterConversion = true;
2785                         }
2786                     }
2787 
2788                     // this check compares parameter lists correctly (see below)
2789                     for (int p = 0; p < arguments.Count; ++p)
2790                     {
2791                         CandidateParameter thisParam = this.signature[p];
2792                         CandidateParameter otherParam = other.signature[p];
2793 
2794                         if (!thisParam.Equals(otherParam))
2795                             signaturesAreIdentical = false;
2796 
2797                         int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]);
2798                         if (conversionResult < 0)
2799                         {
2800                             // A conversion was found that was worse, so this candidate is not better.
2801                             hasAtLeastOneWorseConversion = true;
2802                         }
2803                         else if (conversionResult > 0)
2804                         {
2805                             // This candidate had at least one conversion that was better.  (But
2806                             // we have to keep looking in case there's one that's worse.)
2807                             hasAtLeastOneBetterConversion = true;
2808                         }
2809                     }
2810                     if (hasAtLeastOneBetterConversion && !hasAtLeastOneWorseConversion)
2811                     {
2812                         // At least one conversion was better than the "other" candidate
2813                         // and no other arguments were worse, so this one is better.
2814                         return better;
2815                     }
2816                     else if (!hasAtLeastOneBetterConversion && hasAtLeastOneWorseConversion)
2817                     {
2818                         // At least one conversion was worse than the "other" candidate
2819                         // and no other arguments were better, so this one is worse.
2820                         return worse;
2821                     }
2822                 }
2823                 else
2824                 {
2825                     // NOTE: this is the original v1 code
2826                     // It doesn't check for worse parameters correctly.
2827                     // However, for backwards compatability, we can't change it
2828                     for (int p = 0; p < arguments.Count; ++p)
2829                     {
2830                         CandidateParameter thisParam = this.signature[p];
2831                         CandidateParameter otherParam = other.signature[p];
2832 
2833                         if (!thisParam.Equals(otherParam))
2834                             signaturesAreIdentical = false;
2835 
2836                         int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]);
2837                         if (conversionResult < 0)
2838                         {
2839                             // A conversion was found that was worse, so this candidate is not better.
2840                             return worse;
2841                         }
2842                         else if (conversionResult > 0)
2843                         {
2844                             // This candidate had at least one conversion that was better.  (But
2845                             // we have to keep looking in case there's one that's worse.)
2846                             hasAtLeastOneBetterConversion = true;
2847                         }
2848                     }
2849 
2850                     if (hasAtLeastOneBetterConversion)
2851                     {
2852                         // At least one conversion was better than the "other" candidate, so this one
2853                         // is better.
2854                         return better;
2855                     }
2856                 }
2857 
2858                 if (signaturesAreIdentical)
2859                 {
2860                     // The signatures were "tied".  Try some disambiguating rules for expanded signatures
2861                     // vs normal signatures.
2862                     if (this.form == Form.Normal && other.form == Form.Expanded)
2863                     {
2864                         // This candidate matched in its normal form, but the other one matched only after
2865                         // expansion of a params array.  This one is better.
2866                         return better;
2867                     }
2868                     else if (this.form == Form.Expanded && other.form == Form.Normal)
2869                     {
2870                         // This candidate matched in its expanded form, but the other one matched in its
2871                         // normal form.  The other one was better.
2872                         return worse;
2873                     }
2874                     else if (this.form == Form.Expanded && other.form == Form.Expanded)
2875                     {
2876                         // Both candidates matched in their expanded forms.
2877 
2878                         int thisParameterCount = this.memberParameters.Length;
2879                         int otherParameterCount = other.memberParameters.Length;
2880 
2881                         if (thisParameterCount > otherParameterCount)
2882                         {
2883                             // This candidate had more declared parameters, so it is better.
2884                             return better;
2885                         }
2886                         else if (otherParameterCount > thisParameterCount)
2887                         {
2888                             // The other candidate had more declared parameters, so it was better.
2889                             return worse;
2890                         }
2891                     }
2892                 }
2893 
2894                 // Nothing worked, the two candidates are equally applicable.
2895                 return equal;
2896             }
2897 
MatchNameSpace(string[] test, string[] reference)2898             private static int MatchNameSpace(string[] test, string[] reference)
2899             {
2900                 // returns the number of strings in test that are the same as reference
2901                 int i;
2902                 int len = Math.Min(test.Length, reference.Length);
2903                 for (i = 0; i < len; ++i)
2904                 {
2905                     if (test[i] != reference[i])
2906                         break;
2907                 }
2908                 return i;
2909             }
2910         }
2911 
2912         // Get the candidate target types, ordered from most-derived to least-derived.
GetCandidateTargetTypes(Type targetType)2913         private static List<Type> GetCandidateTargetTypes(Type targetType)
2914         {
2915             List<Type> candidateTypes;
2916 
2917             if (targetType.IsInterface)
2918             {
2919                 candidateTypes = new List<Type>();
2920                 candidateTypes.Add(targetType);
2921 
2922                 // Add all base interfaces in its hierarchy to the candidate list.
2923                 for (int i = 0; i < candidateTypes.Count; ++i)
2924                 {
2925                     Type currentCandidate = candidateTypes[i];
2926                     candidateTypes.AddRange(currentCandidate.GetInterfaces());
2927                 }
2928 
2929                 // Finally, add "System.Object", since all types intrinsically derive from this.
2930                 candidateTypes.Add(typeof(object));
2931             }
2932             else
2933             {
2934                 // It was a class; just add the one class.
2935                 candidateTypes = new List<Type>(1);
2936                 candidateTypes.Add(targetType);
2937             }
2938 
2939             return candidateTypes;
2940         }
2941 
BuildArgCountMismatchError(string name, int numArguments)2942         private delegate ValidationError BuildArgCountMismatchError(string name, int numArguments);
2943 
EvaluateCandidate(List<CandidateMember> candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List<Argument> arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError)2944         private static void EvaluateCandidate(List<CandidateMember> candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List<Argument> arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError)
2945         {
2946             error = null;
2947 
2948             int numArguments = arguments.Count;
2949             string candidateName = candidateMember.Name;
2950 
2951             if (parameters == null || parameters.Length == 0)
2952             {
2953                 // If there were no arguments supplied, and this method has no parameters,
2954                 // then it's a candidate.  (It should be the only one.)
2955                 if (numArguments == 0)
2956                 {
2957                     candidates.Add(new CandidateMember(candidateMember));
2958                 }
2959                 else
2960                 {
2961                     error = buildArgCountMismatchError(candidateName, numArguments);
2962                 }
2963             }
2964             else
2965             {
2966                 List<CandidateParameter> signature = new List<CandidateParameter>();
2967 
2968                 int parameterCount = parameters.Length;
2969 
2970                 int fixedParameterCount = parameterCount;
2971 
2972                 // Check to see if the last parameter is (1) an array and (2) has a ParamArrayAttribute
2973                 // (i.e., it is a "params" array).
2974                 ParameterInfo lastParam = parameters[parameterCount - 1];
2975                 if (lastParam.ParameterType.IsArray)
2976                 {
2977                     object[] attrs = lastParam.GetCustomAttributes(typeof(ParamArrayAttribute), false);
2978                     if (attrs != null && attrs.Length > 0)
2979                         fixedParameterCount -= 1;
2980                 }
2981 
2982                 if (numArguments < fixedParameterCount)
2983                 {
2984                     // Not enough arguments were passed for this to be a candidate.
2985                     error = buildArgCountMismatchError(candidateName, numArguments);
2986 
2987                     return;
2988                 }
2989                 else if (fixedParameterCount == parameterCount && numArguments != parameterCount)
2990                 {
2991                     // Too many arguments were passed for this to be a candidate.
2992                     error = buildArgCountMismatchError(candidateName, numArguments);
2993 
2994                     return;
2995                 }
2996 
2997                 // For the fixed part of the method signature, make sure each argument can
2998                 // be implicitly converted to the corresponding parameter.
2999                 int p = 0;
3000                 for (; p < fixedParameterCount; ++p)
3001                 {
3002                     CandidateParameter candidateParam = new CandidateParameter(parameters[p]);
3003                     if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error))
3004                         break; // argument #p didn't match
3005 
3006                     // If we get here, then so far so good.
3007                     signature.Add(candidateParam);
3008                 }
3009 
3010                 if (p != fixedParameterCount)
3011                 {
3012                     // We didn't match all of the fixed part.  This method is not a candidate.
3013                     return;
3014                 }
3015 
3016                 if (fixedParameterCount < parameterCount)
3017                 {
3018                     // The last parameter was a "params" array.  As long as zero or more arguments
3019                     // are assignable, it's a valid candidate in the expanded form.
3020 
3021                     CandidateMember candidateMethod = null;
3022 
3023                     if (numArguments == fixedParameterCount)
3024                     {
3025                         // Zero arguments were passed as the params array.  The method is a candidate
3026                         // in its expanded form.
3027                         candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
3028                     }
3029                     else if (numArguments == parameterCount)
3030                     {
3031                         // Special case:  one argument was passed as the params array.
3032                         CandidateParameter candidateParam = new CandidateParameter(lastParam);
3033                         if (candidateParam.Match(arguments[p], candidateName, p + 1, out error))
3034                         {
3035                             // It was the same array type as the params array, so the candidate
3036                             // matched in its normal form.
3037                             signature.Add(candidateParam);
3038                             candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal);
3039                         }
3040                     }
3041 
3042                     if (candidateMethod == null)
3043                     {
3044                         // One or more arguments were passed as the params array.  As long
3045                         // as they match the element type, this method is a candidate.
3046                         CandidateParameter candidateParam = new CandidateParameter(lastParam.ParameterType.GetElementType());
3047 
3048                         for (; p < numArguments; ++p)
3049                         {
3050                             if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error))
3051                             {
3052                                 // Not all of the trailing arguments matched the params array's element type;
3053                                 // this cannot be a candidate.
3054                                 return;
3055                             }
3056 
3057                             // If we get here, then so far so good.
3058                             signature.Add(candidateParam);
3059                         }
3060 
3061                         // All the trailing arguments matched, so this is a candidate in the expanded form.
3062                         candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
3063                     }
3064 
3065                     candidates.Add(candidateMethod);
3066                 }
3067                 else
3068                 {
3069                     // The last parameter wasn't "params".  This candidate matched in its normal form.
3070                     candidates.Add(new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal));
3071                 }
3072             }
3073         }
3074 
FindBestCandidate(Type targetType, List<CandidateMember> candidates, List<Argument> arguments)3075         private CandidateMember FindBestCandidate(Type targetType, List<CandidateMember> candidates, List<Argument> arguments)
3076         {
3077             int numCandidates = candidates.Count;
3078             Debug.Assert(numCandidates > 0, "expected at least one candidate");
3079 
3080             // Start by assuming the first candidate is the best one.
3081             List<CandidateMember> bestCandidates = new List<CandidateMember>(1);
3082             bestCandidates.Add(candidates[0]);
3083 
3084             // Go through the rest of the candidates and try to find a better one.  (If
3085             // there are no more candidates, then there was only one, and that's the right
3086             // one.)
3087             for (int i = 1; i < numCandidates; ++i)
3088             {
3089                 CandidateMember newCandidate = candidates[i];
3090 
3091                 // Compare this new candidate one if the current "best" ones.  (If there
3092                 // is currently more than one best candidate, then so far its ambiguous, which
3093                 // means all the best ones are equally good.  Thus if this new candidate
3094                 // is better than one, it's better than all.
3095                 CandidateMember bestCandidate = bestCandidates[0];
3096 
3097                 int comparison = newCandidate.CompareMember(targetType, bestCandidate, arguments, this);
3098                 if (comparison > 0)
3099                 {
3100                     // The new one was better than at least one of the best ones.  It
3101                     // becomes the new best one.
3102                     bestCandidates.Clear();
3103                     bestCandidates.Add(newCandidate);
3104                 }
3105                 else if (comparison == 0)
3106                 {
3107                     // The new one was no better, so add it to the list of current best.
3108                     // (Unless we find a better one, it's ambiguous so far.)
3109                     bestCandidates.Add(newCandidate);
3110                 }
3111             }
3112 
3113             if (bestCandidates.Count == 1)
3114             {
3115                 // Good, there was exactly one best match.
3116                 return bestCandidates[0];
3117             }
3118 
3119             // Otherwise, it must have been ambiguous.
3120             return null;
3121         }
3122 
FindBestCandidate(Type targetType, List<MethodInfo> methods, params Type[] types)3123         internal MethodInfo FindBestCandidate(Type targetType, List<MethodInfo> methods, params Type[] types)
3124         {
3125             List<Argument> arguments = new List<Argument>();
3126             foreach (Type t in types)
3127                 arguments.Add(new Argument(t));
3128 
3129             List<CandidateMember> candidates = new List<CandidateMember>(methods.Count);
3130             foreach (MethodInfo method in methods)
3131             {
3132                 ValidationError tempError = null;
3133                 EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
3134                                   delegate(string name, int numArguments)
3135                                   {
3136                                       string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments);
3137                                       return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
3138                                   });
3139             }
3140             if (candidates.Count == 0)
3141             {
3142                 // nothing looks useful
3143                 return null;
3144             }
3145             CandidateMember result = FindBestCandidate(targetType, candidates, arguments);
3146             return (result != null) ? (MethodInfo)result.Member : null;
3147         }
3148 
ResolveConstructor(Type targetType, BindingFlags constructorBindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)3149         internal RuleConstructorExpressionInfo ResolveConstructor(Type targetType, BindingFlags constructorBindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)
3150         {
3151             string message;
3152 
3153             List<Argument> arguments = new List<Argument>(argumentExprs.Count);
3154             foreach (CodeExpression argumentExpr in argumentExprs)
3155                 arguments.Add(new Argument(argumentExpr, this));
3156 
3157             // Get the candidate types and all candidate methods contained in them.
3158             List<Type> candidateTypes = GetCandidateTargetTypes(targetType);
3159             // Get all methods by this name...
3160             List<ConstructorInfo> constructors = GetConstructors(candidateTypes, constructorBindingFlags);
3161             if (constructors.Count == 0)
3162             {
3163                 message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(targetType));
3164                 error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists);
3165                 return null;
3166             }
3167 
3168             // Cull the list of methods to those which match the supplied arguments.
3169             List<CandidateMember> candidateConstructors = GetCandidateConstructors(constructors, arguments, out error);
3170 
3171             // If the list is null, then no candidates matched.
3172             if (candidateConstructors == null)
3173                 return null;
3174 
3175             // We found candidate methods in this type.
3176             CandidateMember bestCandidate = FindBestCandidate(targetType, candidateConstructors, arguments);
3177 
3178             if (bestCandidate == null)
3179             {
3180                 // It was ambiguous.
3181                 message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousConstructor, RuleDecompiler.DecompileType(targetType));
3182                 error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
3183                 return null;
3184             }
3185 
3186             // We found the best match.
3187             return new RuleConstructorExpressionInfo((ConstructorInfo)bestCandidate.Member, bestCandidate.IsExpanded);
3188         }
3189 
ResolveMethod(Type targetType, string methodName, BindingFlags methodBindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)3190         internal RuleMethodInvokeExpressionInfo ResolveMethod(Type targetType, string methodName, BindingFlags methodBindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)
3191         {
3192             string message;
3193 
3194             List<Argument> arguments = new List<Argument>(argumentExprs.Count);
3195             foreach (CodeExpression argumentExpr in argumentExprs)
3196                 arguments.Add(new Argument(argumentExpr, this));
3197 
3198             // Get the candidate types and all candidate methods contained in them.
3199             List<Type> candidateTypes = GetCandidateTargetTypes(targetType);
3200             // Get all methods by this name...
3201             List<MethodInfo> methods = GetNamedMethods(candidateTypes, methodName, methodBindingFlags);
3202             if (methods.Count == 0)
3203             {
3204                 message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownMethod, methodName, RuleDecompiler.DecompileType(targetType));
3205                 error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists);
3206                 return null;
3207             }
3208 
3209             // Cull the list of methods to those which match the supplied arguments.
3210             List<CandidateMember> candidateMethods = GetCandidateMethods(methodName, methods, arguments, out error);
3211 
3212             // If the list is null, then no candidates matched.
3213             if (candidateMethods == null)
3214                 return null;
3215 
3216             // We found candidate methods in this type.
3217             CandidateMember bestCandidate = FindBestCandidate(targetType, candidateMethods, arguments);
3218 
3219             if (bestCandidate == null)
3220             {
3221                 // It was ambiguous.
3222                 message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousMatch, methodName);
3223                 error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
3224 
3225                 return null;
3226             }
3227 
3228             // We found the best match.
3229             MethodInfo theMethod = (MethodInfo)bestCandidate.Member;
3230             if (theMethod != null)
3231             {
3232                 IsAuthorized(theMethod.ReturnType);
3233             }
3234             return new RuleMethodInvokeExpressionInfo(theMethod, bestCandidate.IsExpanded);
3235         }
3236 
GetConstructors(List<Type> targetTypes, BindingFlags constructorBindingFlags)3237         internal static List<ConstructorInfo> GetConstructors(List<Type> targetTypes, BindingFlags constructorBindingFlags)
3238         {
3239             List<ConstructorInfo> methods = new List<ConstructorInfo>();
3240 
3241             for (int t = 0; t < targetTypes.Count; ++t)
3242             {
3243                 Type targetType = targetTypes[t];
3244 
3245                 // Go through all the constructors on the target type
3246                 ConstructorInfo[] members = targetType.GetConstructors(constructorBindingFlags);
3247                 for (int m = 0; m < members.Length; ++m)
3248                 {
3249                     ConstructorInfo constructor = members[m];
3250                     if (constructor.IsGenericMethod) // skip generic constructors
3251                         continue;
3252                     if (constructor.IsStatic) // skip static constructors
3253                         continue;
3254                     if (constructor.IsPrivate) // skip private constructors
3255                         continue;
3256                     if (constructor.IsFamily) // skip internal constructors
3257                         continue;
3258                     methods.Add(constructor);
3259                 }
3260             }
3261             return methods;
3262         }
3263 
GetNamedMethods(List<Type> targetTypes, string methodName, BindingFlags methodBindingFlags)3264         private List<MethodInfo> GetNamedMethods(List<Type> targetTypes, string methodName, BindingFlags methodBindingFlags)
3265         {
3266             List<MethodInfo> methods = new List<MethodInfo>();
3267             List<ExtensionMethodInfo> currentExtensionMethods = ExtensionMethods;
3268             for (int t = 0; t < targetTypes.Count; ++t)
3269             {
3270                 Type targetType = targetTypes[t];
3271 
3272                 // Go through all the methods on the target type that have matching names.
3273                 MemberInfo[] members = targetType.GetMember(methodName, MemberTypes.Method, methodBindingFlags);
3274                 for (int m = 0; m < members.Length; ++m)
3275                 {
3276                     MethodInfo method = (MethodInfo)members[m];
3277                     if (!method.IsGenericMethod) // skip generic methods
3278                         methods.Add(method);
3279                 }
3280 
3281                 // add in any extension methods that match
3282                 foreach (ExtensionMethodInfo extension in currentExtensionMethods)
3283                 {
3284                     // does it have the right name and is the type compatible
3285                     ValidationError error;
3286                     if ((extension.Name == methodName) &&
3287                         TypesAreAssignable(targetType, extension.AssumedDeclaringType, null, out error))
3288                     {
3289                         // possible match
3290                         methods.Add(extension);
3291                     }
3292                 }
3293             }
3294 
3295             return methods;
3296         }
3297 
3298         private List<ExtensionMethodInfo> extensionMethods;
3299         private List<Assembly> seenAssemblies;
3300         private const string ExtensionAttributeFullName = "System.Runtime.CompilerServices.ExtensionAttribute, " + AssemblyRef.SystemCore;
3301         private Type extensionAttribute;
3302 
3303         private static Type defaultExtensionAttribute = GetDefaultExtensionAttribute();
3304 
GetDefaultExtensionAttribute()3305         private static Type GetDefaultExtensionAttribute()
3306         {
3307             return Type.GetType(ExtensionAttributeFullName, false);
3308         }
3309 
3310         // The extensionAttributeType may still be null after calling this method
3311         // if, for example, we are in a 3.0 SP2 environment.
SetExtensionAttribute()3312         private void SetExtensionAttribute()
3313         {
3314             // use the TypeProvider first
3315             extensionAttribute = typeProvider.GetType(ExtensionAttributeFullName, false);
3316             if (extensionAttribute == null)
3317             {
3318                 extensionAttribute = defaultExtensionAttribute;
3319             }
3320         }
3321 
3322         internal List<ExtensionMethodInfo> ExtensionMethods
3323         {
3324             get
3325             {
3326                 if (extensionMethods == null)
3327                     DetermineExtensionMethods();
3328 
3329                 return extensionMethods;
3330             }
3331         }
3332 
DetermineExtensionMethods()3333         private void DetermineExtensionMethods()
3334         {
3335             extensionMethods = new List<ExtensionMethodInfo>();
3336 
3337             SetExtensionAttribute();
3338             if (extensionAttribute != null)
3339             {
3340                 seenAssemblies = new List<Assembly>();
3341                 Assembly localAssembly = typeProvider.LocalAssembly;
3342                 if (localAssembly != null)
3343                 {
3344                     DetermineExtensionMethods(localAssembly);
3345                     foreach (Assembly a in typeProvider.ReferencedAssemblies)
3346                         DetermineExtensionMethods(a);
3347                 }
3348                 else
3349                 {
3350                     // probably at design-time, nothing compiled yet
3351                     // go through all types it knows about
3352                     DetermineExtensionMethods(typeProvider.GetTypes());
3353                 }
3354             }
3355         }
3356 
DetermineExtensionMethods(Assembly assembly)3357         internal void DetermineExtensionMethods(Assembly assembly)
3358         {
3359             // when this method is called outside of this class, we must have tried
3360             // getting ExtensionMethods. So we must have tried setting extensionAttributeType.
3361 
3362             if (extensionAttribute != null)
3363             {
3364                 if ((assembly != null) && (!seenAssemblies.Contains(assembly)))
3365                 {
3366                     seenAssemblies.Add(assembly);
3367                     if (IsMarkedExtension(assembly))
3368                     {
3369                         Type[] types;
3370                         try
3371                         {
3372                             types = assembly.GetTypes();
3373                         }
3374                         catch (ReflectionTypeLoadException e)
3375                         {
3376                             // problems loading all the types, take what we can get
3377                             // some types will be null
3378                             types = e.Types;
3379                         }
3380                         DetermineExtensionMethods(types);
3381                     }
3382                 }
3383             }
3384         }
3385 
DetermineExtensionMethods(Type[] types)3386         private void DetermineExtensionMethods(Type[] types)
3387         {
3388             foreach (Type type in types)
3389             {
3390                 // static classes are defined as "abstract sealed"
3391                 // Note: VB doesn't support static classes, so the modules are only defined as "sealed"
3392                 if ((type != null) && (type.IsPublic || type.IsNestedPublic) && (type.IsSealed) && (IsMarkedExtension(type)))
3393                 {
3394                     // looks like a class containing extension methods, let's find them
3395                     MethodInfo[] staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
3396                     foreach (MethodInfo mi in staticMethods)
3397                     {
3398                         // skip generic methods
3399                         if ((mi.IsStatic) && !(mi.IsGenericMethod) && (IsMarkedExtension(mi)))
3400                         {
3401                             ParameterInfo[] parms = mi.GetParameters();
3402                             if (parms.Length > 0 && parms[0].ParameterType != null)
3403                             {
3404                                 extensionMethods.Add(new ExtensionMethodInfo(mi, parms));
3405                             }
3406                         }
3407                     }
3408                 }
3409             }
3410         }
3411 
IsMarkedExtension(Assembly assembly)3412         private bool IsMarkedExtension(Assembly assembly)
3413         {
3414             if (extensionAttribute != null)
3415             {
3416                 object[] objAttrs = assembly.GetCustomAttributes(extensionAttribute, false);
3417                 if (objAttrs != null && objAttrs.Length > 0)
3418                     return true;
3419             }
3420 
3421             return false;
3422         }
3423 
IsMarkedExtension(Type type)3424         private bool IsMarkedExtension(Type type)
3425         {
3426             if (extensionAttribute != null)
3427             {
3428                 object[] objAttrs = type.GetCustomAttributes(extensionAttribute, false);
3429                 if (objAttrs != null && objAttrs.Length > 0)
3430                     return true;
3431             }
3432 
3433             return false;
3434         }
3435 
IsMarkedExtension(MethodInfo mi)3436         private bool IsMarkedExtension(MethodInfo mi)
3437         {
3438             if (extensionAttribute != null)
3439             {
3440                 object[] objAttrs = mi.GetCustomAttributes(extensionAttribute, false);
3441                 if (objAttrs != null && objAttrs.Length > 0)
3442                     return true;
3443             }
3444 
3445             return false;
3446         }
3447 
GetCandidateMethods(string methodName, List<MethodInfo> methods, List<Argument> arguments, out ValidationError error)3448         static List<CandidateMember> GetCandidateMethods(string methodName, List<MethodInfo> methods, List<Argument> arguments, out ValidationError error)
3449         {
3450             List<CandidateMember> candidates = new List<CandidateMember>();
3451 
3452             error = null;
3453 
3454             int errorCount = 0;
3455             foreach (MethodInfo method in methods)
3456             {
3457                 ValidationError tempError = null;
3458                 EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
3459                                   delegate(string name, int numArguments)
3460                                   {
3461                                       string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments);
3462                                       return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
3463                                   });
3464 
3465                 error = tempError;
3466                 if (tempError != null)
3467                     ++errorCount;
3468             }
3469 
3470             if (candidates.Count == 0)
3471             {
3472                 // No candidates were found.
3473 
3474                 if (errorCount > 1)
3475                 {
3476                     // If multiple candidates generated errors, then use a more generic error that says
3477                     // we couldn't find a matching overload.
3478                     string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodOverloadNotFound, methodName);
3479                     error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound);
3480                 }
3481 
3482                 return null;
3483             }
3484             else
3485             {
3486                 // If there are any candidates, then wipe out any errors left over from any mismatches.
3487                 error = null;
3488             }
3489 
3490             return candidates;
3491         }
3492 
GetCandidateConstructors(List<ConstructorInfo> constructors, List<Argument> arguments, out ValidationError error)3493         static List<CandidateMember> GetCandidateConstructors(List<ConstructorInfo> constructors, List<Argument> arguments, out ValidationError error)
3494         {
3495             List<CandidateMember> candidates = new List<CandidateMember>();
3496 
3497             error = null;
3498 
3499             int errorCount = 0;
3500             foreach (ConstructorInfo method in constructors)
3501             {
3502                 ValidationError tempError = null;
3503                 EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
3504                                   delegate(string name, int numArguments)
3505                                   {
3506                                       string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments);
3507                                       return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
3508                                   });
3509 
3510                 error = tempError;
3511                 if (tempError != null)
3512                     ++errorCount;
3513             }
3514 
3515             if (candidates.Count == 0)
3516             {
3517                 // No candidates were found.
3518 
3519                 if (errorCount > 1)
3520                 {
3521                     // If multiple candidates generated errors, then use a more generic error that says
3522                     // we couldn't find a matching overload.
3523                     string message = string.Format(CultureInfo.CurrentCulture, Messages.ConstructorOverloadNotFound);
3524                     error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound);
3525                 }
3526 
3527                 return null;
3528             }
3529             else
3530             {
3531                 // If there are any candidates, then wipe out any errors left over from any mismatches.
3532                 error = null;
3533             }
3534 
3535             return candidates;
3536         }
3537 
ResolveIndexerProperty(Type targetType, BindingFlags bindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)3538         internal RulePropertyExpressionInfo ResolveIndexerProperty(Type targetType, BindingFlags bindingFlags, List<CodeExpression> argumentExprs, out ValidationError error)
3539         {
3540             string message;
3541 
3542             int numArgs = argumentExprs.Count;
3543 
3544             if (numArgs < 1)
3545             {
3546                 // Must have at least one indexer!
3547                 message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArgs);
3548                 error = new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch);
3549                 return null;
3550             }
3551 
3552             List<Argument> arguments = new List<Argument>(numArgs);
3553             foreach (CodeExpression argumentExpr in argumentExprs)
3554                 arguments.Add(new Argument(argumentExpr, this));
3555 
3556             // Get the candidate types and all the candidate indexer properties contained in them.
3557             List<Type> candidateTypes = GetCandidateTargetTypes(targetType);
3558             List<PropertyInfo> indexerProperties = GetIndexerProperties(candidateTypes, bindingFlags);
3559             if (indexerProperties.Count == 0)
3560             {
3561                 message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerNotFound, RuleDecompiler.DecompileType(targetType));
3562                 error = new ValidationError(message, ErrorNumbers.Error_IndexerNotFound);
3563                 return null;
3564             }
3565 
3566             List<CandidateMember> candidateIndexers = GetCandidateIndexers(indexerProperties, arguments, out error);
3567 
3568             // If the list is null, then no candidates matched.
3569             if (candidateIndexers == null)
3570                 return null;
3571 
3572             // We found candidate methods in this type.
3573             CandidateMember bestCandidate = FindBestCandidate(targetType, candidateIndexers, arguments);
3574 
3575             if (bestCandidate == null)
3576             {
3577                 // It was ambiguous.
3578                 message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousIndexerMatch);
3579                 error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
3580 
3581                 return null;
3582             }
3583 
3584             // We found the best match.
3585             PropertyInfo pi = (PropertyInfo)bestCandidate.Member;
3586             if (pi != null)
3587             {
3588                 IsAuthorized(pi.PropertyType);
3589             }
3590             return new RulePropertyExpressionInfo(pi, pi.PropertyType, bestCandidate.IsExpanded);
3591         }
3592 
GetIndexerProperties(List<Type> candidateTypes, BindingFlags bindingFlags)3593         private static List<PropertyInfo> GetIndexerProperties(List<Type> candidateTypes, BindingFlags bindingFlags)
3594         {
3595             List<PropertyInfo> indexerProperties = new List<PropertyInfo>();
3596 
3597             foreach (Type targetType in candidateTypes)
3598             {
3599                 object[] attrs = targetType.GetCustomAttributes(typeof(DefaultMemberAttribute), true);
3600                 if (attrs == null || attrs.Length == 0)
3601                     continue;
3602 
3603                 DefaultMemberAttribute[] defaultMemberAttrs = (DefaultMemberAttribute[])attrs;
3604 
3605                 PropertyInfo[] properties = targetType.GetProperties(bindingFlags);
3606                 for (int p = 0; p < properties.Length; ++p)
3607                 {
3608                     PropertyInfo pi = properties[p];
3609 
3610                     // Select only those properties whose name matches the default name.
3611                     bool matchedName = false;
3612                     for (int dm = 0; dm < defaultMemberAttrs.Length; ++dm)
3613                     {
3614                         if (defaultMemberAttrs[dm].MemberName == pi.Name)
3615                         {
3616                             matchedName = true;
3617                             break;
3618                         }
3619                     }
3620 
3621                     if (matchedName)
3622                     {
3623                         // We matched the name...
3624                         ParameterInfo[] indexerParameters = pi.GetIndexParameters();
3625                         if (indexerParameters.Length > 0)
3626                         {
3627                             // ... and have indexer parameters; therefore, this is
3628                             // an interesting property.
3629                             indexerProperties.Add(pi);
3630                         }
3631                     }
3632                 }
3633             }
3634 
3635             return indexerProperties;
3636         }
3637 
GetCandidateIndexers(List<PropertyInfo> indexerProperties, List<Argument> arguments, out ValidationError error)3638         private static List<CandidateMember> GetCandidateIndexers(List<PropertyInfo> indexerProperties, List<Argument> arguments, out ValidationError error)
3639         {
3640             List<CandidateMember> candidates = new List<CandidateMember>();
3641 
3642             error = null;
3643 
3644             int errorCount = 0;
3645             foreach (PropertyInfo indexerProp in indexerProperties)
3646             {
3647                 ValidationError tempError = null;
3648                 EvaluateCandidate(candidates, indexerProp, indexerProp.GetIndexParameters(), arguments, out tempError,
3649                                   delegate(string propName, int numArguments)
3650                                   {
3651                                       string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArguments);
3652                                       return new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch);
3653                                   });
3654 
3655                 error = tempError;
3656                 if (tempError != null)
3657                     ++errorCount;
3658             }
3659 
3660             if (candidates.Count == 0)
3661             {
3662                 // No candidates were found.
3663 
3664                 if (errorCount > 1)
3665                 {
3666                     // If multiple candidates generated errors, then use a more generic error that says
3667                     // we couldn't find a matching overload.
3668                     string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerOverloadNotFound);
3669                     error = new ValidationError(message, ErrorNumbers.Error_IndexerOverloadNotFound);
3670                 }
3671 
3672                 return null;
3673             }
3674             else
3675             {
3676                 // If there are any candidates, then wipe out any errors left over from any mismatches.
3677                 error = null;
3678             }
3679 
3680             return candidates;
3681         }
3682 
3683         #endregion
3684 
3685         #region Type resolution
3686 
AddTypeReference(CodeTypeReference typeRef, Type type)3687         internal void AddTypeReference(CodeTypeReference typeRef, Type type)
3688         {
3689             typeRefMap[typeRef] = type;
3690         }
3691 
ResolveType(CodeTypeReference typeRef)3692         internal Type ResolveType(CodeTypeReference typeRef)
3693         {
3694             Type resultType = null;
3695 
3696             if (!typeRefMap.TryGetValue(typeRef, out resultType))
3697             {
3698                 string message;
3699 
3700                 resultType = FindType(typeRef.BaseType);
3701 
3702                 if (resultType == null)
3703                 {
3704                     // check if we have a qualifiedname saved, and if we do, use it
3705                     string qualifiedName = typeRef.UserData[RuleUserDataKeys.QualifiedName] as string;
3706                     resultType = ResolveType(qualifiedName);
3707                     if (resultType != null)
3708                     {
3709                         // qualified name returned the complete type, save it and we're done
3710                         typeRefMap.Add(typeRef, resultType);
3711                         return resultType;
3712                     }
3713                     message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownType, typeRef.BaseType);
3714                     ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType);
3715                     error.UserData[RuleUserDataKeys.ErrorObject] = typeRef;
3716                     Errors.Add(error);
3717                     return null;
3718                 }
3719 
3720                 // Handle generic type arguments.
3721                 if (typeRef.TypeArguments.Count > 0)
3722                 {
3723                     Type[] typeArguments = new Type[typeRef.TypeArguments.Count];
3724                     for (int i = 0; i < typeRef.TypeArguments.Count; ++i)
3725                     {
3726                         // design-time types don't have fully-qualified names, so when they are
3727                         // used in a generic CodeTypeReference constructor leaves them with []
3728                         // surrounding them. Remove the [] if possible
3729                         CodeTypeReference arg = typeRef.TypeArguments[i];
3730                         if (arg.BaseType.StartsWith("[", StringComparison.Ordinal))
3731                             arg.BaseType = arg.BaseType.Substring(1, arg.BaseType.Length - 2);
3732 
3733                         typeArguments[i] = ResolveType(arg);
3734                         if (typeArguments[i] == null)
3735                             return null;
3736                     }
3737 
3738                     resultType = resultType.MakeGenericType(typeArguments);
3739                     if (resultType == null)
3740                     {
3741                         StringBuilder sb = new StringBuilder(typeRef.BaseType);
3742                         string prefix = "<";
3743                         foreach (Type t in typeArguments)
3744                         {
3745                             sb.Append(prefix);
3746                             prefix = ",";
3747                             sb.Append(RuleDecompiler.DecompileType(t));
3748                         }
3749                         sb.Append(">");
3750                         message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownGenericType, sb.ToString());
3751                         ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType);
3752                         error.UserData[RuleUserDataKeys.ErrorObject] = typeRef;
3753                         Errors.Add(error);
3754                         return null;
3755                     }
3756                 }
3757 
3758 
3759                 if (resultType != null)
3760                 {
3761                     CodeTypeReference arrayTypeRef = typeRef;
3762                     if (arrayTypeRef.ArrayRank > 0)
3763                     {
3764                         do
3765                         {
3766                             resultType = (arrayTypeRef.ArrayRank == 1) ? resultType.MakeArrayType() : resultType.MakeArrayType(arrayTypeRef.ArrayRank);
3767 
3768                             arrayTypeRef = arrayTypeRef.ArrayElementType;
3769                         } while (arrayTypeRef.ArrayRank > 0);
3770                     }
3771                 }
3772 
3773                 if (resultType != null)
3774                 {
3775                     typeRefMap.Add(typeRef, resultType);
3776 
3777                     // at runtime we may not have the assembly loaded, so keep the fully qualified name around
3778                     typeRef.UserData[RuleUserDataKeys.QualifiedName] = resultType.AssemblyQualifiedName;
3779                 }
3780             }
3781 
3782             return resultType;
3783         }
3784 
ResolveType(string qualifiedName)3785         internal Type ResolveType(string qualifiedName)
3786         {
3787             Type resultType = null;
3788             if (qualifiedName != null)
3789             {
3790                 resultType = typeProvider.GetType(qualifiedName, false);
3791 
3792                 // if the Typeprovider can't find it, use the framework,
3793                 // since it should be an AssemblyQualifiedName
3794                 if (resultType == null)
3795                     resultType = Type.GetType(qualifiedName, false);
3796 
3797             }
3798             return resultType;
3799         }
3800 
FindType(string typeName)3801         private Type FindType(string typeName)
3802         {
3803             if (typeName == null)
3804                 throw new ArgumentNullException("typeName");
3805 
3806             Type type = null;
3807 
3808             // do we know about this type
3809             if (!typesUsed.TryGetValue(typeName, out type))
3810             {
3811                 type = typeProvider.GetType(typeName, false);
3812 
3813                 if (type != null)
3814                 {
3815                     typesUsed.Add(typeName, type);
3816 
3817                     IsAuthorized(type);
3818                 }
3819             }
3820 
3821             return type;
3822         }
3823 
IsAuthorized(Type type)3824         internal void IsAuthorized(Type type)
3825         {
3826             Debug.Assert(!type.IsPointer && !type.IsByRef,
3827             "IsAuthorized should not be called for a type that is a pointer or passed by reference : " + type.AssemblyQualifiedName);
3828             if (checkStaticType)
3829             {
3830                 if (authorizedTypes == null)
3831                 {
3832                     ValidationError error = new ValidationError(Messages.Error_ConfigFileMissingOrInvalid, ErrorNumbers.Error_ConfigFileMissingOrInvalid);
3833                     Errors.Add(error);
3834                 }
3835                 else
3836                 {
3837                     while (type.IsArray)
3838                     {
3839                         type = type.GetElementType();
3840                     }
3841                     if (type.IsGenericType)
3842                     {
3843                         IsAuthorizedSimpleType(type.GetGenericTypeDefinition());
3844                         Type[] typeArguments = type.GetGenericArguments();
3845                         foreach (Type t in typeArguments)
3846                         {
3847                             IsAuthorized(t);
3848                         }
3849                     }
3850                     else
3851                     {
3852                         IsAuthorizedSimpleType(type);
3853                     }
3854                 }
3855             }
3856         }
3857 
IsAuthorizedSimpleType(Type type)3858         void IsAuthorizedSimpleType(Type type)
3859         {
3860             Debug.Assert((!type.IsGenericType || type.IsGenericTypeDefinition) && !type.HasElementType,
3861                 "IsAuthorizedSimpleType should not be called for a partially specialized generic type or a type that encompasses or refers to another type : " +
3862                 type.AssemblyQualifiedName);
3863 
3864             string qualifiedName = type.AssemblyQualifiedName;
3865 
3866             if (!typesUsedAuthorized.ContainsKey(qualifiedName))
3867             {
3868                 bool authorized = false;
3869                 foreach (AuthorizedType authorizedType in authorizedTypes)
3870                 {
3871                     if (authorizedType.RegularExpression.IsMatch(qualifiedName))
3872                     {
3873                         authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0);
3874                         if (!authorized)
3875                             break;
3876                     }
3877                 }
3878                 if (!authorized)
3879                 {
3880                     string message = string.Format(CultureInfo.CurrentCulture, Messages.Error_TypeNotAuthorized, type.FullName);
3881                     ValidationError error = new ValidationError(message, ErrorNumbers.Error_TypeNotAuthorized);
3882                     error.UserData[RuleUserDataKeys.ErrorObject] = type;
3883                     Errors.Add(error);
3884                 }
3885                 else
3886                 {
3887                     typesUsedAuthorized.Add(qualifiedName, type);
3888                 }
3889             }
3890         }
3891 
3892         #endregion
3893 
3894         #endregion
3895     }
3896     #endregion RuleValidator
3897 }
3898