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; }
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; }