public IType Resolve(ITypeResolveContext context) { foreach (var asm in context.Compilation.Assemblies) { foreach (var attr in asm.AssemblyAttributes.Where(a => a.AttributeType.FullName == XmlnsDefinitionAttribute && a.PositionalArguments.Count == 2)) { ConstantResolveResult crr = attr.PositionalArguments[0] as ConstantResolveResult; ConstantResolveResult crr2 = attr.PositionalArguments[1] as ConstantResolveResult; if (crr == null || crr2 == null) { continue; } string namespaceName = crr2.ConstantValue as string; if (xmlNamespace.Equals(crr.ConstantValue as string, StringComparison.OrdinalIgnoreCase) && namespaceName != null) { ITypeDefinition td = asm.GetTypeDefinition(namespaceName, localName, 0); if (td != null) { return(td); } } } } return(new UnknownType(null, localName, 0)); }
public JsNode VisitConstantResolveResult(ConstantResolveResult res) { var nodes = res.GetNodes(); if (res.Type is DefaultTypeParameter) { return(Js.Member("Default").Invoke(SkJs.EntityTypeRefToMember(res.Type))); } if (res.Type != null && res.Type.Kind == TypeKind.Enum) { var enumMembers = res.Type.GetFields(); var me = enumMembers.Where(t => (t.ConstantValue != null) && t.ConstantValue.Equals(res.ConstantValue)).FirstOrDefault(); if (me != null) { return(Visit(me.AccessSelf()));//.Access().Member(c.CreateTypeRef(en), defaultEnumMember); } //TODO: //return Visit(JsTypeImporter.GetValueTypeInitializer(res.Type, Project)); } //var nodes = res.GetNodes(); //if (nodes.IsNotNullOrEmpty()) //{ // var node = nodes[0]; // if (node != null && node is PrimitiveExpression) // { // var node2 = Visit(node); //use literal value instead // return node2; // } //} return(Js.Value(res.ConstantValue)); }
public JsNode VisitConstantResolveResult(ConstantResolveResult res) { if (res.Type is DefaultTypeParameter) { return(Js.Member("Default").Invoke(SkJs.EntityTypeRefToMember(res.Type))); } if (res.Type != null && res.Type.Kind == TypeKind.Enum) { var enumMembers = res.Type.GetFields(); var me = enumMembers.Where(t => (t.ConstantValue != null) && t.ConstantValue.Equals(res.ConstantValue)).FirstOrDefault(); if (me != null) { return(Visit(me.AccessSelf()));//.Access().Member(c.CreateTypeRef(en), defaultEnumMember); } //TODO: //return Visit(JsTypeImporter.GetValueTypeInitializer(res.Type, Project)); } var nodes = res.GetNodes(); if (nodes.IsNotNullOrEmpty()) { if (nodes[0] != null) { bool isPrimitiveExpr = nodes[0] is PrimitiveExpression; if (!isPrimitiveExpr) { return(Js.Value(res.ConstantValue, string.Format(" /* {0} */", nodes[0].ToString()))); } } } return(Js.Value(res.ConstantValue)); }
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(_ => _.Namespace).Returns(argExpression.Type.Namespace); argType.SetupGet(_ => _.Name).Returns(argExpression.Type.Name); 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); }
private void ProcessPositionalArgs(IList <ResolveResult> args) { if (args.Count == 0) { return; } Console.WriteLine("attribute.PositionalArguments :"); for (Int32 index = 0; index < args.Count; ++index) { ResolveResult argResult = args[index]; Console.Write("index = {0}, type = {1}", index, argResult.GetType()); if (argResult is ConstantResolveResult) { ConstantResolveResult constResult = (ConstantResolveResult)argResult; Console.Write(", value = {0}", constResult.ConstantValue); } if (argResult is MemberResolveResult) { MemberResolveResult memberResult = (MemberResolveResult)argResult; IMember member = memberResult.Member; Console.Write(", value = {0}, memberKind = {1}, typeKind = {2}", member.Name, member.SymbolKind, memberResult.Type.Kind); } Console.WriteLine(); } }
public void NullableConversion_BasedOnImplicitEnumerationConversion() { ResolveResult zero = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 0); ResolveResult one = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1); Assert.AreEqual(C.EnumerationConversion(true, true), conversions.ExplicitConversion(zero, compilation.FindType(typeof(StringComparison?)))); Assert.AreEqual(C.EnumerationConversion(false, true), conversions.ExplicitConversion(one, compilation.FindType(typeof(StringComparison?)))); }
public object VisitConstantResolveResult(ConstantResolveResult res) { if (res.Type.Kind == TypeKind.Enum) { var value = Enum.ToObject(res.Type.GetMirroredClrType(), res.ConstantValue); return(value); } return(res.ConstantValue); }
bool AreEqualConstants(ConstantResolveResult c1, ConstantResolveResult c2) { if (c1 == null || c2 == null) { return(false); } CSharpResolver r = new CSharpResolver(resolveVisitor.TypeResolveContext, resolveVisitor.CancellationToken); ResolveResult c = r.ResolveBinaryOperator(BinaryOperatorType.Equality, c1, c2); return(c.IsCompileTimeConstant && (c.ConstantValue as bool?) == true); }
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); }
/// <summary> /// Evaluates an expression. /// </summary> /// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns> bool?EvaluateCondition(Expression expr) { ConstantResolveResult rr = EvaluateConstant(expr); if (rr != null) { return(rr.ConstantValue as bool?); } else { return(null); } }
private bool NeedExportDefaultValueExpression(ConstantResolveResult res) { // 值类型 default 处理 // 但是传给 C# 的时候,也许传 null 会更好 if (res.Type.Kind == TypeKind.Struct) { // 过滤 Nullable if (res.Type.FullName != "System.Nullable") { return(true); } } return(false); }
public JNode VisitConstantResolveResult(ConstantResolveResult res) { var nodes = res.GetNodes(); if (res.Type is DefaultTypeParameter) { return(J.Member("Default").Invoke(JNaming.JAccess(res.Type))); } if (res.Type != null && res.Type.Kind == TypeKind.Enum) { return(Visit(JTypeImporter.GetValueTypeInitializer(res.Type, Compiler))); } //var nodes = res.GetNodes(); //if (nodes.IsNotNullOrEmpty()) //{ // var node = nodes[0]; // if (node != null && node is PrimitiveExpression) // { // var node2 = Visit(node); //use literal value instead // return node2; // } //} return(J.Value(res.ConstantValue)); }
public void NullableConversion_BasedOnImplicitEnumerationConversion() { ResolveResult zero = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 0); ResolveResult one = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1); Assert.AreEqual(C.EnumerationConversion(true, true), conversions.ExplicitConversion(zero, compilation.FindType(typeof(StringComparison?)))); Assert.AreEqual(C.EnumerationConversion(false, true), conversions.ExplicitConversion(one, compilation.FindType(typeof(StringComparison?)))); }
int BetterConversion(object value, Type t1, Type t2) { IType fromType = value.GetType().ToTypeReference().Resolve(ctx); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); IType t1Type = t1.ToTypeReference().Resolve(ctx); IType t2Type = t2.ToTypeReference().Resolve(ctx); return conversions.BetterConversion(crr, t1Type, t2Type); }
public virtual TResult VisitConstantResolveResult(ConstantResolveResult rr, TData data) { VisitChildResolveResults(rr, data); return(default(TResult)); }
public void EnumerationConversion() { ResolveResult zero = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 0); ResolveResult one = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1); C implicitEnumerationConversion = C.EnumerationConversion(true, false); Assert.AreEqual(implicitEnumerationConversion, conversions.ImplicitConversion(zero, compilation.FindType(typeof(StringComparison)))); Assert.AreEqual(C.None, conversions.ImplicitConversion(one, compilation.FindType(typeof(StringComparison)))); }
bool IntegerLiteralConversion(object value, Type to) { IType fromType = compilation.FindType(value.GetType()); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); IType to2 = compilation.FindType(to); return conversions.ImplicitConversion(crr, to2).IsValid; }
int BetterConversion(object value, Type t1, Type t2) { IType fromType = compilation.FindType(value.GetType()); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); IType t1Type = compilation.FindType(t1); IType t2Type = compilation.FindType(t2); return conversions.BetterConversion(crr, t1Type, t2Type); }
public override DefiniteAssignmentStatus VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, DefiniteAssignmentStatus data) { if (binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalAnd) { // Handle constant left side of && expressions (not in the C# spec, but done by the MS compiler) bool?cond = analysis.EvaluateCondition(binaryOperatorExpression.Left); if (cond == true) { return(binaryOperatorExpression.Right.AcceptVisitor(this, data)); // right operand gets evaluated unconditionally } else if (cond == false) { return(data); // right operand never gets evaluated } // C# 4.0 spec: §5.3.3.24 Definite Assignment for && expressions DefiniteAssignmentStatus afterLeft = binaryOperatorExpression.Left.AcceptVisitor(this, data); DefiniteAssignmentStatus beforeRight; if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression) { beforeRight = DefiniteAssignmentStatus.DefinitelyAssigned; } else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression) { beforeRight = DefiniteAssignmentStatus.PotentiallyAssigned; } else { beforeRight = afterLeft; } DefiniteAssignmentStatus afterRight = binaryOperatorExpression.Right.AcceptVisitor(this, beforeRight); if (afterLeft == DefiniteAssignmentStatus.DefinitelyAssigned) { return(DefiniteAssignmentStatus.DefinitelyAssigned); } else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned && afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression) { return(DefiniteAssignmentStatus.DefinitelyAssigned); } else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned || afterRight == DefiniteAssignmentStatus.AssignedAfterTrueExpression) { return(DefiniteAssignmentStatus.AssignedAfterTrueExpression); } else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression && afterRight == DefiniteAssignmentStatus.AssignedAfterFalseExpression) { return(DefiniteAssignmentStatus.AssignedAfterFalseExpression); } else { return(DefiniteAssignmentStatus.PotentiallyAssigned); } } else if (binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalOr) { // C# 4.0 spec: §5.3.3.25 Definite Assignment for || expressions bool?cond = analysis.EvaluateCondition(binaryOperatorExpression.Left); if (cond == false) { return(binaryOperatorExpression.Right.AcceptVisitor(this, data)); // right operand gets evaluated unconditionally } else if (cond == true) { return(data); // right operand never gets evaluated } DefiniteAssignmentStatus afterLeft = binaryOperatorExpression.Left.AcceptVisitor(this, data); DefiniteAssignmentStatus beforeRight; if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression) { beforeRight = DefiniteAssignmentStatus.PotentiallyAssigned; } else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression) { beforeRight = DefiniteAssignmentStatus.DefinitelyAssigned; } else { beforeRight = afterLeft; } DefiniteAssignmentStatus afterRight = binaryOperatorExpression.Right.AcceptVisitor(this, beforeRight); if (afterLeft == DefiniteAssignmentStatus.DefinitelyAssigned) { return(DefiniteAssignmentStatus.DefinitelyAssigned); } else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned && afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression) { return(DefiniteAssignmentStatus.DefinitelyAssigned); } else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned || afterRight == DefiniteAssignmentStatus.AssignedAfterFalseExpression) { return(DefiniteAssignmentStatus.AssignedAfterFalseExpression); } else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression && afterRight == DefiniteAssignmentStatus.AssignedAfterTrueExpression) { return(DefiniteAssignmentStatus.AssignedAfterTrueExpression); } else { return(DefiniteAssignmentStatus.PotentiallyAssigned); } } else if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) { // C# 4.0 spec: §5.3.3.27 Definite assignment for ?? expressions ConstantResolveResult crr = analysis.EvaluateConstant(binaryOperatorExpression.Left); if (crr != null && crr.ConstantValue == null) { return(binaryOperatorExpression.Right.AcceptVisitor(this, data)); } DefiniteAssignmentStatus status = CleanSpecialValues(binaryOperatorExpression.Left.AcceptVisitor(this, data)); binaryOperatorExpression.Right.AcceptVisitor(this, status); return(status); } else { // use default logic for other operators return(VisitChildren(binaryOperatorExpression, data)); } }
SwitchStatement TranslateSwitch(BlockContainer switchContainer, SwitchInstruction inst) { Debug.Assert(switchContainer.EntryPoint.IncomingEdgeCount == 1); var oldBreakTarget = breakTarget; breakTarget = switchContainer; // 'break' within a switch would only leave the switch var oldCaseLabelMapping = caseLabelMapping; caseLabelMapping = new Dictionary <Block, ConstantResolveResult>(); TranslatedExpression value; var strToInt = inst.Value as StringToInt; if (strToInt != null) { value = exprBuilder.Translate(strToInt.Argument); } else { value = exprBuilder.Translate(inst.Value); } // Pick the section with the most labels as default section. IL.SwitchSection defaultSection = inst.Sections.First(); foreach (var section in inst.Sections) { if (section.Labels.Count() > defaultSection.Labels.Count()) { defaultSection = section; } } var stmt = new SwitchStatement() { Expression = value }; Dictionary <IL.SwitchSection, Syntax.SwitchSection> translationDictionary = new Dictionary <IL.SwitchSection, Syntax.SwitchSection>(); // initialize C# switch sections. foreach (var section in inst.Sections) { // This is used in the block-label mapping. ConstantResolveResult firstValueResolveResult; var astSection = new Syntax.SwitchSection(); // Create case labels: if (section == defaultSection) { astSection.CaseLabels.Add(new CaseLabel()); firstValueResolveResult = null; } else { var values = section.Labels.Values.Select(i => CreateTypedCaseLabel(i, value.Type, strToInt?.Map)).ToArray(); if (section.HasNullLabel) { astSection.CaseLabels.Add(new CaseLabel(new NullReferenceExpression())); firstValueResolveResult = new ConstantResolveResult(SpecialType.NullType, null); } else { Debug.Assert(values.Length > 0); firstValueResolveResult = values[0]; } astSection.CaseLabels.AddRange(values.Select(label => new CaseLabel(exprBuilder.ConvertConstantValue(label, allowImplicitConversion: true)))); } switch (section.Body) { case Branch br: // we can only inline the block, if all branches are in the switchContainer. if (br.TargetBlock.Parent == switchContainer && switchContainer.Descendants.OfType <Branch>().Where(b => b.TargetBlock == br.TargetBlock).All(b => BlockContainer.FindClosestSwitchContainer(b) == switchContainer)) { caseLabelMapping.Add(br.TargetBlock, firstValueResolveResult); } break; default: break; } translationDictionary.Add(section, astSection); stmt.SwitchSections.Add(astSection); } foreach (var section in inst.Sections) { var astSection = translationDictionary[section]; switch (section.Body) { case Branch br: // we can only inline the block, if all branches are in the switchContainer. if (br.TargetBlock.Parent == switchContainer && switchContainer.Descendants.OfType <Branch>().Where(b => b.TargetBlock == br.TargetBlock).All(b => BlockContainer.FindClosestSwitchContainer(b) == switchContainer)) { ConvertSwitchSectionBody(astSection, br.TargetBlock); } else { ConvertSwitchSectionBody(astSection, section.Body); } break; case Leave leave: if (astSection.CaseLabels.Count == 1 && astSection.CaseLabels.First().Expression.IsNull&& leave.TargetContainer == switchContainer) { stmt.SwitchSections.Remove(astSection); break; } goto default; default: ConvertSwitchSectionBody(astSection, section.Body); break; } } if (switchContainer != null) { // Translate any remaining blocks: var lastSectionStatements = stmt.SwitchSections.Last().Statements; foreach (var block in switchContainer.Blocks.Skip(1)) { if (caseLabelMapping.ContainsKey(block)) { continue; } lastSectionStatements.Add(new LabelStatement { Label = block.Label }); foreach (var nestedInst in block.Instructions) { var nestedStmt = Convert(nestedInst); if (nestedStmt is BlockStatement b) { foreach (var nested in b.Statements) { lastSectionStatements.Add(nested.Detach()); } } else { lastSectionStatements.Add(nestedStmt); } } Debug.Assert(block.FinalInstruction.OpCode == OpCode.Nop); } if (endContainerLabels.TryGetValue(switchContainer, out string label)) { lastSectionStatements.Add(new LabelStatement { Label = label }); lastSectionStatements.Add(new BreakStatement()); } } breakTarget = oldBreakTarget; caseLabelMapping = oldCaseLabelMapping; return(stmt); }
Conversion IntegerLiteralConversion(object value, Type to) { IType fromType = value.GetType().ToTypeReference().Resolve(ctx); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); IType to2 = to.ToTypeReference().Resolve(ctx); return conversions.ImplicitConversion(crr, to2); }
public void EnumBitwiseOrWithMissingBaseType() { var resolver = new CSharpResolver(enumWithMissingBaseType.Compilation); var lhs = new ConstantResolveResult(enumWithMissingBaseType, 1); var rhs = new ConstantResolveResult(enumWithMissingBaseType, 2); var rr = (ConstantResolveResult)resolver.ResolveBinaryOperator(BinaryOperatorType.BitwiseOr, lhs, rhs); Assert.AreEqual(enumWithMissingBaseType, rr.Type); Assert.AreEqual(3, rr.ConstantValue); }
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) 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 override JsExpression VisitConstantResolveResult(ConstantResolveResult rr, object data) { return MakeConstant(rr); }
public virtual object VisitConstantResolveResult(ConstantResolveResult rr, object data) { VisitChildResolveResults(rr, data); return(null); }
public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data) { // First, figure out which switch section will get called (if the expression is constant): ConstantResolveResult constant = builder.EvaluateConstant(switchStatement.Expression); SwitchSection defaultSection = null; SwitchSection sectionMatchedByConstant = null; foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (CaseLabel label in section.CaseLabels) { if (label.Expression.IsNull) { defaultSection = section; } else if (constant != null) { ConstantResolveResult labelConstant = builder.EvaluateConstant(label.Expression); if (builder.AreEqualConstants(constant, labelConstant)) { sectionMatchedByConstant = section; } } } } if (constant != null && sectionMatchedByConstant == null) { sectionMatchedByConstant = defaultSection; } int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false); breakTargets.Push(end); foreach (SwitchSection section in switchStatement.SwitchSections) { if (constant == null || section == sectionMatchedByConstant) { HandleStatementList(section.Statements, data); } else { // This section is unreachable: pass null to HandleStatementList. HandleStatementList(section.Statements, null); } // Don't bother connecting the ends of the sections: the 'break' statement takes care of that. } breakTargets.Pop(); if (defaultSection == null && sectionMatchedByConstant == null) { Connect(data, end); } if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { // Resolve 'goto case' statements: throw new NotImplementedException(); } builder.nodes.Add(end); return(end); }
public override string VisitConstantResolveResult(ConstantResolveResult rr, object data) { return(MakeConstant(rr)); }
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].GetConstantValue()); } 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 ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression) { if (SpecialType.Dynamic.Equals(expression.Type)) 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); } 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.SByte && 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) { // 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); } CSharpOperators.UnaryOperatorMethod m = (CSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate; IType resultType = m.ReturnType; if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) { // If there are any user-defined operators, prefer those over the built-in operators. // It'll be a more informative error. if (userDefinedOperatorOR.BestCandidate != null) return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR); 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); }