Пример #1
0
		private static IList<IAttribute> CreateMockAttributes(IEnumerable<Expression<Func<System.Attribute>>> attributes) {
			var result = new List<IAttribute>();
			if (attributes != null) {
				foreach (var attrExpression in attributes) {
					var attr = new Mock<IAttribute>(MockBehavior.Strict);
					var body = (NewExpression)attrExpression.Body;
					attr.SetupGet(_ => _.AttributeType).Returns(CreateMockTypeDefinition(body.Type.FullName, null));
					var posArgs = new List<ResolveResult>();
					foreach (var argExpression in body.Arguments) {
						var argType = new Mock<IType>(MockBehavior.Strict);
						argType.SetupGet(_ => _.FullName).Returns(argExpression.Type.FullName);
						var arg = new ConstantResolveResult(argType.Object, ((ConstantExpression)argExpression).Value);
						posArgs.Add(arg);
					}
					attr.SetupGet(_ => _.PositionalArguments).Returns(posArgs);

					if (body.Members != null && body.Members.Count > 0)
						throw new InvalidOperationException("Named attribute args are not supported");

					attr.SetupGet(_ => _.NamedArguments).Returns(new KeyValuePair<IMember, ResolveResult>[0]);

					result.Add(attr.Object);
				}
			}
			return result;
		}
Пример #2
0
		public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
		{
			if (expression.Type.Kind == TypeKind.Dynamic)
				return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);
			
			// C# 4.0 spec: §7.3.3 Unary operator overload resolution
			string overloadableOperatorName = GetOverloadableOperatorName(op);
			if (overloadableOperatorName == null) {
				switch (op) {
					case UnaryOperatorType.Dereference:
						PointerType p = expression.Type as PointerType;
						if (p != null)
							return UnaryOperatorResolveResult(p.ElementType, op, expression);
						else
							return ErrorResult;
					case UnaryOperatorType.AddressOf:
						return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
					case UnaryOperatorType.Await:
						ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, true);
						ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]);
						var getResultMethodGroup = CreateMemberLookup().Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
						if (getResultMethodGroup != null) {
							var or = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
							IType awaitResultType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
							return UnaryOperatorResolveResult(awaitResultType, UnaryOperatorType.Await, expression);
						} else {
							return UnaryOperatorResolveResult(SpecialType.UnknownType, UnaryOperatorType.Await, expression);
						}
					default:
						throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
				}
			}
			// If the type is nullable, get the underlying type:
			IType type = NullableType.GetUnderlyingType(expression.Type);
			bool isNullable = NullableType.IsNullable(expression.Type);
			
			// the operator is overloadable:
			OverloadResolution userDefinedOperatorOR = new OverloadResolution(compilation, new[] { expression }, conversions: conversions);
			foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) {
				userDefinedOperatorOR.AddCandidate(candidate);
			}
			if (userDefinedOperatorOR.FoundApplicableCandidate) {
				return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
			}
			
			expression = UnaryNumericPromotion(op, ref type, isNullable, expression);
			CppOperators.OperatorMethod[] methodGroup;
			CppOperators operators = CppOperators.Get(compilation);
			switch (op) {
				case UnaryOperatorType.Increment:
				case UnaryOperatorType.Decrement:
				case UnaryOperatorType.PostIncrement:
				case UnaryOperatorType.PostDecrement:
					// C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
					// C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
					TypeCode code = ReflectionHelper.GetTypeCode(type);
					if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
						return UnaryOperatorResolveResult(expression.Type, op, expression);
					else
						return new ErrorResolveResult(expression.Type);
				case UnaryOperatorType.Plus:
					methodGroup = operators.UnaryPlusOperators;
					break;
				case UnaryOperatorType.Minus:
					methodGroup = CheckForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators;
					break;
				case UnaryOperatorType.Not:
					methodGroup = operators.LogicalNegationOperators;
					break;
				case UnaryOperatorType.BitNot:
					if (type.Kind == TypeKind.Enum) {
						if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) {
							// evaluate as (E)(~(U)x);
							var U = compilation.FindType(expression.ConstantValue.GetType());
							var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
							return CheckErrorAndResolveCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
						} else {
							return UnaryOperatorResolveResult(expression.Type, op, expression);
						}
					} else {
						methodGroup = operators.BitwiseComplementOperators;
						break;
					}
				default:
					throw new InvalidOperationException();
			}
			OverloadResolution builtinOperatorOR = new OverloadResolution(compilation, new[] { expression }, conversions: conversions);
			foreach (var candidate in methodGroup) {
				builtinOperatorOR.AddCandidate(candidate);
			}
			CppOperators.UnaryOperatorMethod m = (CppOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate;
			IType resultType = m.ReturnType;
			if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) {
				if (userDefinedOperatorOR.BestCandidate != null) {
					// If there are any user-defined operators, prefer those over the built-in operators.
					// It'll be a more informative error.
					return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
				} else if (builtinOperatorOR.BestCandidateAmbiguousWith != null) {
					// If the best candidate is ambiguous, just use the input type instead
					// of picking one of the ambiguous overloads.
					return new ErrorResolveResult(expression.Type);
				} else {
					return new ErrorResolveResult(resultType);
				}
			} else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
				object val;
				try {
					val = m.Invoke(this, expression.ConstantValue);
				} catch (ArithmeticException) {
					return new ErrorResolveResult(resultType);
				}
				return new ConstantResolveResult(resultType, val);
			} else {
				expression = Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
				return UnaryOperatorResolveResult(resultType, op, expression);
			}
		}
 /// <summary>
 /// Resolves an array creation.
 /// </summary>
 /// <param name="elementType">
 /// The array element type.
 /// Pass null to resolve an implicitly-typed array creation.
 /// </param>
 /// <param name="sizeArguments">
 /// The size arguments.
 /// The length of this array will be used as the number of dimensions of the array type.
 /// Negative values will be treated as errors.
 /// </param>
 /// <param name="initializerElements">
 /// The initializer elements. May be null if no array initializer was specified.
 /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
 /// </param>
 public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int[] sizeArguments, ResolveResult[] initializerElements = null)
 {
     ResolveResult[] sizeArgResults = new ResolveResult[sizeArguments.Length];
     for (int i = 0; i < sizeArguments.Length; i++) {
         if (sizeArguments[i] < 0)
             sizeArgResults[i] = ErrorResolveResult.UnknownError;
         else
             sizeArgResults[i] = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), sizeArguments[i]);
     }
     return ResolveArrayCreation(elementType, sizeArgResults, initializerElements);
 }
		public override IList<ResolveResult> GetArgumentsForCall()
		{
			ResolveResult[] results = new ResolveResult[Member.Parameters.Count];
			List<ResolveResult> paramsArguments = IsExpandedForm ? new List<ResolveResult>() : null;
			// map arguments to parameters:
			for (int i = 0; i < Arguments.Count; i++) {
				int mappedTo;
				if (argumentToParameterMap != null)
					mappedTo = argumentToParameterMap[i];
				else
					mappedTo = IsExpandedForm ? Math.Min(i, results.Length - 1) : i;
				
				if (mappedTo >= 0 && mappedTo < results.Length) {
					if (IsExpandedForm && mappedTo == results.Length - 1)
						paramsArguments.Add(Arguments[i]);
					else
						results[mappedTo] = Arguments[i];
				}
			}
			if (IsExpandedForm)
				results[results.Length - 1] = new ArrayCreateResolveResult(Member.Parameters.Last().Type, null, paramsArguments.ToArray());
			
			for (int i = 0; i < results.Length; i++) {
				if (results[i] == null) {
					if (Member.Parameters[i].IsOptional) {
						results[i] = new ConstantResolveResult(Member.Parameters[i].Type, Member.Parameters[i].ConstantValue);
					} else {
						results[i] = ErrorResolveResult.UnknownError;
					}
				}
			}
			
			return results;
		}
		public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
		{
			if (expression.Type.Kind == TypeKind.Dynamic) {
				if (op == UnaryOperatorType.Await) {
					return new AwaitResolveResult(SpecialType.Dynamic, new DynamicInvocationResolveResult(new DynamicMemberResolveResult(expression, "GetAwaiter"), DynamicInvocationType.Invocation, EmptyList<ResolveResult>.Instance), SpecialType.Dynamic, null, null, null);
				}
				else {
					return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);
				}
			}
			
			// C# 4.0 spec: §7.3.3 Unary operator overload resolution
			string overloadableOperatorName = GetOverloadableOperatorName(op);
			if (overloadableOperatorName == null) {
				switch (op) {
					case UnaryOperatorType.Dereference:
						PointerType p = expression.Type as PointerType;
						if (p != null)
							return UnaryOperatorResolveResult(p.ElementType, op, expression);
						else
							return ErrorResult;
					case UnaryOperatorType.AddressOf:
						return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
					case UnaryOperatorType.Await: {
						ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
						ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0], argumentNames: null, allowOptionalParameters: false);

						var lookup = CreateMemberLookup();
						IMethod getResultMethod;
						IType awaitResultType;
						var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
						if (getResultMethodGroup != null) {
							var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
							getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null;
							awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType;
						}
						else {
							getResultMethod = null;
							awaitResultType = SpecialType.UnknownType;
						}

						var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false);
						var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null);
						if (isCompletedProperty != null && (!isCompletedProperty.ReturnType.IsKnownType(KnownTypeCode.Boolean) || !isCompletedProperty.CanGet))
							isCompletedProperty = null;

						var interfaceOnCompleted = compilation.FindType(KnownTypeCode.INotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "OnCompleted");
						var interfaceUnsafeOnCompleted = compilation.FindType(KnownTypeCode.ICriticalNotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "UnsafeOnCompleted");

						IMethod onCompletedMethod = null;
						var candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceUnsafeOnCompleted)).ToList();
						if (candidates.Count == 0) {
							candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceOnCompleted)).ToList();
							if (candidates.Count == 1)
								onCompletedMethod = candidates[0];
						}
						else if (candidates.Count == 1) {
							onCompletedMethod = candidates[0];
						}

						return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod);
					}

					default:
						throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
				}
			}
			// If the type is nullable, get the underlying type:
			IType type = NullableType.GetUnderlyingType(expression.Type);
			bool isNullable = NullableType.IsNullable(expression.Type);
			
			// the operator is overloadable:
			OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { expression });
			foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) {
				userDefinedOperatorOR.AddCandidate(candidate);
			}
			if (userDefinedOperatorOR.FoundApplicableCandidate) {
				return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
			}
			
			expression = UnaryNumericPromotion(op, ref type, isNullable, expression);
			CSharpOperators.OperatorMethod[] methodGroup;
			CSharpOperators operators = CSharpOperators.Get(compilation);
			switch (op) {
				case UnaryOperatorType.Increment:
				case UnaryOperatorType.Decrement:
				case UnaryOperatorType.PostIncrement:
				case UnaryOperatorType.PostDecrement:
					// C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
					// C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
					TypeCode code = ReflectionHelper.GetTypeCode(type);
					if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
						return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
					else
						return new ErrorResolveResult(expression.Type);
				case UnaryOperatorType.Plus:
					methodGroup = operators.UnaryPlusOperators;
					break;
				case UnaryOperatorType.Minus:
					methodGroup = CheckForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators;
					break;
				case UnaryOperatorType.Not:
					methodGroup = operators.LogicalNegationOperators;
					break;
				case UnaryOperatorType.BitNot:
					if (type.Kind == TypeKind.Enum) {
						if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) {
							// evaluate as (E)(~(U)x);
							var U = compilation.FindType(expression.ConstantValue.GetType());
							var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
							return CheckErrorAndResolveUncheckedCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
						} else {
							return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
						}
					} else {
						methodGroup = operators.BitwiseComplementOperators;
						break;
					}
				default:
					throw new InvalidOperationException();
			}
			OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { expression });
			foreach (var candidate in methodGroup) {
				builtinOperatorOR.AddCandidate(candidate);
			}
			CSharpOperators.UnaryOperatorMethod m = (CSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate;
			IType resultType = m.ReturnType;
			if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) {
				if (userDefinedOperatorOR.BestCandidate != null) {
					// If there are any user-defined operators, prefer those over the built-in operators.
					// It'll be a more informative error.
					return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
				} else if (builtinOperatorOR.BestCandidateAmbiguousWith != null) {
					// If the best candidate is ambiguous, just use the input type instead
					// of picking one of the ambiguous overloads.
					return new ErrorResolveResult(expression.Type);
				} else {
					return new ErrorResolveResult(resultType);
				}
			} else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
				object val;
				try {
					val = m.Invoke(this, expression.ConstantValue);
				} catch (ArithmeticException) {
					return new ErrorResolveResult(resultType);
				}
				return new ConstantResolveResult(resultType, val);
			} else {
				expression = Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
				return UnaryOperatorResolveResult(resultType, op, expression,
				                                  builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator);
			}
		}
		public override IList<ResolveResult> GetArgumentsForCall()
		{
			ResolveResult[] results = new ResolveResult[Member.Parameters.Count];
			List<ResolveResult> paramsArguments = IsExpandedForm ? new List<ResolveResult>() : null;
			// map arguments to parameters:
			for (int i = 0; i < Arguments.Count; i++) {
				int mappedTo;
				if (argumentToParameterMap != null)
					mappedTo = argumentToParameterMap[i];
				else
					mappedTo = IsExpandedForm ? Math.Min(i, results.Length - 1) : i;
				
				if (mappedTo >= 0 && mappedTo < results.Length) {
					if (IsExpandedForm && mappedTo == results.Length - 1) {
						paramsArguments.Add(Arguments[i]);
					} else {
						var narr = Arguments[i] as NamedArgumentResolveResult;
						if (narr != null)
							results[mappedTo] = narr.Argument;
						else
							results[mappedTo] = Arguments[i];
					}
				}
			}
			if (IsExpandedForm){
				IType arrayType = Member.Parameters.Last().Type;
				IType int32 = Member.Compilation.FindType(KnownTypeCode.Int32);
				ResolveResult[] sizeArguments = { new ConstantResolveResult(int32, paramsArguments.Count) };
				results[results.Length - 1] = new ArrayCreateResolveResult(arrayType, sizeArguments, paramsArguments);
			}
			
			for (int i = 0; i < results.Length; i++) {
				if (results[i] == null) {
					if (Member.Parameters[i].IsOptional) {
						results[i] = new ConstantResolveResult(Member.Parameters[i].Type, Member.Parameters[i].ConstantValue);
					} else {
						results[i] = ErrorResolveResult.UnknownError;
					}
				}
			}
			
			return results;
		}