public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var mre = invocationExpression.Target as MemberReferenceExpression; var method = invocationExpression.GetSymbol() as IMethod; if (method == null || !method.IsExtensionMethod || mre == null || !(mre.Target is TypeReferenceExpression) || !invocationExpression.Arguments.Any()) { return; } var firstArgument = invocationExpression.Arguments.First(); var target = firstArgument.GetResolveResult(); var args = invocationExpression.Arguments.Skip(1).Select(a => a.GetResolveResult()).ToArray(); var rr = resolver.ResolveMemberAccess(target, method.Name, method.TypeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult; if (rr == null) { return; } var or = rr.PerformOverloadResolution(resolveContext.Compilation, args, allowExtensionMethods: true); if (or == null || or.IsAmbiguous) { return; } if (firstArgument is NullReferenceExpression) { firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } else { mre.Target = firstArgument.Detach(); } }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var mre = invocationExpression.Target as MemberReferenceExpression; var method = invocationExpression.GetSymbol() as IMethod; if (method == null || !method.IsExtensionMethod || mre == null || !(mre.Target is TypeReferenceExpression) || !invocationExpression.Arguments.Any()) { return; } var typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; var firstArgument = invocationExpression.Arguments.First(); var target = firstArgument.GetResolveResult(); var args = invocationExpression.Arguments.Skip(1).Select(a => a.GetResolveResult()).ToArray(); if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args)) { return; } if (firstArgument is NullReferenceExpression) { firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } else { mre.Target = firstArgument.Detach(); } }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var method = invocationExpression.GetSymbol() as IMethod; if (method == null || !method.IsExtensionMethod || !invocationExpression.Arguments.Any()) { return; } IReadOnlyList <IType> typeArguments; MemberReferenceExpression memberRefExpr; switch (invocationExpression.Target) { case MemberReferenceExpression mre: typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = mre; break; case IdentifierExpression ide: typeArguments = ide.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = null; break; default: return; } var firstArgument = invocationExpression.Arguments.First(); var target = firstArgument.GetResolveResult(); if (target is ConstantResolveResult crr && crr.ConstantValue == null) { target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion); } var args = invocationExpression.Arguments.Skip(1).Select(a => a.GetResolveResult()).ToArray(); if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args)) { return; } if (firstArgument is NullReferenceExpression) { firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } if (invocationExpression.Target is IdentifierExpression identifierExpression) { identifierExpression.Detach(); memberRefExpr = new MemberReferenceExpression(firstArgument.Detach(), method.Name, identifierExpression.TypeArguments.Detach()); invocationExpression.Target = memberRefExpr; } else { memberRefExpr.Target = firstArgument.Detach(); } }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); if (!CanTransformToExtensionMethodCall(resolver, invocationExpression, out var memberRefExpr, out var target, out var firstArgument)) { return; } var method = (IMethod)invocationExpression.GetSymbol(); if (firstArgument is DirectionExpression dirExpr) { if (!context.Settings.RefExtensionMethods || dirExpr.FieldDirection == FieldDirection.Out) { return; } firstArgument = dirExpr.Expression; target = firstArgument.GetResolveResult(); dirExpr.Detach(); } else if (firstArgument is NullReferenceExpression) { Debug.Assert(context.RequiredNamespacesSuperset.Contains(method.Parameters[0].Type.Namespace)); firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } if (invocationExpression.Target is IdentifierExpression identifierExpression) { identifierExpression.Detach(); memberRefExpr = new MemberReferenceExpression(firstArgument.Detach(), method.Name, identifierExpression.TypeArguments.Detach()); invocationExpression.Target = memberRefExpr; } else { memberRefExpr.Target = firstArgument.Detach(); } if (invocationExpression.GetResolveResult() is CSharpInvocationResolveResult irr) { // do not forget to update the CSharpInvocationResolveResult => set IsExtensionMethodInvocation == true invocationExpression.RemoveAnnotations <CSharpInvocationResolveResult>(); var newResolveResult = new CSharpInvocationResolveResult( irr.TargetResult, irr.Member, irr.Arguments, irr.OverloadResolutionErrors, isExtensionMethodInvocation: true, irr.IsExpandedForm, irr.IsDelegateInvocation, irr.GetArgumentToParameterMap(), irr.InitializerStatements); invocationExpression.AddAnnotation(newResolveResult); } }
static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, InvocationExpression invocationExpression, out MemberReferenceExpression memberRefExpr, out ResolveResult target, out Expression firstArgument) { var method = invocationExpression.GetSymbol() as IMethod; memberRefExpr = null; target = null; firstArgument = null; if (method == null || !method.IsExtensionMethod || !invocationExpression.Arguments.Any()) { return(false); } IReadOnlyList <IType> typeArguments; switch (invocationExpression.Target) { case MemberReferenceExpression mre: typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = mre; break; case IdentifierExpression ide: typeArguments = ide.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = null; break; default: return(false); } firstArgument = invocationExpression.Arguments.First(); if (firstArgument is NamedArgumentExpression) { return(false); } target = firstArgument.GetResolveResult(); if (target is ConstantResolveResult crr && crr.ConstantValue == null) { target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion); }
void ProcessInvocationExpression(InvocationExpression invocationExpression) { var method = invocationExpression.GetSymbol() as IMethod; if (method == null) { return; } var arguments = invocationExpression.Arguments.ToArray(); // Reduce "String.Concat(a, b)" to "a + b" if (IsStringConcat(method) && CheckArgumentsForStringConcat(arguments)) { bool isInExpressionTree = invocationExpression.Ancestors.OfType <LambdaExpression>().Any( lambda => lambda.Annotation <IL.ILFunction>()?.Kind == IL.ILFunctionKind.ExpressionTree); Expression expr = arguments[0].Detach(); if (!isInExpressionTree) { expr = RemoveRedundantToStringInConcat(expr, method, isLastArgument: false).Detach(); } for (int i = 1; i < arguments.Length; i++) { var arg = arguments[i].Detach(); if (!isInExpressionTree) { arg = RemoveRedundantToStringInConcat(arg, method, isLastArgument: i == arguments.Length - 1).Detach(); } expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arg); } expr.CopyAnnotationsFrom(invocationExpression); invocationExpression.ReplaceWith(expr); return; } switch (method.FullName) { case "System.Type.GetTypeFromHandle": if (arguments.Length == 1) { if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { Expression target = ((MemberReferenceExpression)arguments[0]).Target; target.CopyInstructionsFrom(invocationExpression); invocationExpression.ReplaceWith(target); return; } } break; /* * case "System.Reflection.FieldInfo.GetFieldFromHandle": * // TODO : This is dead code because LdTokenAnnotation is not added anywhere: * if (arguments.Length == 1) { * MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression; * if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation<LdTokenAnnotation>() != null) { * invocationExpression.ReplaceWith(mre.Target); * return; * } * } else if (arguments.Length == 2) { * MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression; * MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression; * if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation<LdTokenAnnotation>() != null) { * if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) { * Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single(); * FieldReference field = oldArg.Annotation<FieldReference>(); * if (field != null) { * AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach(); * oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg)); * invocationExpression.ReplaceWith(mre1.Target); * return; * } * } * } * } * break; */ case "System.Activator.CreateInstance": if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0])) { invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First()))); } break; } BinaryOperatorType?bop = GetBinaryOperatorTypeFromMetadataName(method.Name); if (bop != null && arguments.Length == 2) { invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression invocationExpression.ReplaceWith( new BinaryOperatorExpression( arguments[0].UnwrapInDirectionExpression(), bop.Value, arguments[1].UnwrapInDirectionExpression() ).CopyAnnotationsFrom(invocationExpression) ); return; } UnaryOperatorType?uop = GetUnaryOperatorTypeFromMetadataName(method.Name); if (uop != null && arguments.Length == 1) { if (uop == UnaryOperatorType.Increment || uop == UnaryOperatorType.Decrement) { // `op_Increment(a)` is not equivalent to `++a`, // because it doesn't assign the incremented value to a. if (method.DeclaringType.IsKnownType(KnownTypeCode.Decimal)) { // Legacy csc optimizes "d + 1m" to "op_Increment(d)", // so reverse that optimization here: invocationExpression.ReplaceWith( new BinaryOperatorExpression( arguments[0].UnwrapInDirectionExpression().Detach(), (uop == UnaryOperatorType.Increment ? BinaryOperatorType.Add : BinaryOperatorType.Subtract), new PrimitiveExpression(1m) ).CopyAnnotationsFrom(invocationExpression) ); } return; } arguments[0].Remove(); // detach argument invocationExpression.ReplaceWith( new UnaryOperatorExpression(uop.Value, arguments[0].UnwrapInDirectionExpression()).CopyAnnotationsFrom(invocationExpression) ); return; } if (method.Name == "op_Explicit" && arguments.Length == 1) { arguments[0].Remove(); // detach argument invocationExpression.ReplaceWith( new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.ReturnType), arguments[0].UnwrapInDirectionExpression()) .CopyAnnotationsFrom(invocationExpression) ); return; } if (method.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == Roles.Condition) { invocationExpression.ReplaceWith(arguments[0].UnwrapInDirectionExpression()); return; } return; }
void ProcessInvocationExpression(InvocationExpression invocationExpression) { var method = invocationExpression.GetSymbol() as IMethod; if (method == null) { return; } var arguments = invocationExpression.Arguments.ToArray(); // Reduce "String.Concat(a, b)" to "a + b" if (method.Name == "Concat" && method.DeclaringType.FullName == "System.String" && CheckArgumentsForStringConcat(arguments)) { invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression Expression expr = arguments[0]; for (int i = 1; i < arguments.Length; i++) { expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); } invocationExpression.ReplaceWith(expr); return; } switch (method.FullName) { case "System.Type.GetTypeFromHandle": if (arguments.Length == 1) { if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { Expression target = ((MemberReferenceExpression)arguments[0]).Target; target.CopyInstructionsFrom(invocationExpression); invocationExpression.ReplaceWith(target); return; } } break; case "System.Reflection.FieldInfo.GetFieldFromHandle": if (arguments.Length == 1) { MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression; if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation <LdTokenAnnotation>() != null) { invocationExpression.ReplaceWith(mre.Target); return; } } else if (arguments.Length == 2) { MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression; MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression; if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation <LdTokenAnnotation>() != null) { if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) { Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single(); FieldReference field = oldArg.Annotation <FieldReference>(); if (field != null) { AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach(); oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg)); invocationExpression.ReplaceWith(mre1.Target); return; } } } } break; case "System.Activator.CreateInstance": if (method.TypeArguments.Count == 1 && arguments.Length == 0 && method.TypeArguments[0].Kind == TypeKind.TypeParameter) { invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First()))); } break; } BinaryOperatorType?bop = GetBinaryOperatorTypeFromMetadataName(method.Name); if (bop != null && arguments.Length == 2) { invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression invocationExpression.ReplaceWith( new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).CopyAnnotationsFrom(invocationExpression) ); return; } UnaryOperatorType?uop = GetUnaryOperatorTypeFromMetadataName(method.Name); if (uop != null && arguments.Length == 1) { arguments[0].Remove(); // detach argument invocationExpression.ReplaceWith( new UnaryOperatorExpression(uop.Value, arguments[0]).CopyAnnotationsFrom(invocationExpression) ); return; } if (method.Name == "op_Explicit" && arguments.Length == 1) { arguments[0].Remove(); // detach argument invocationExpression.ReplaceWith( new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.ReturnType), arguments[0]) .CopyAnnotationsFrom(invocationExpression) ); return; } if (method.Name == "op_Implicit" && arguments.Length == 1) { invocationExpression.ReplaceWith(arguments[0]); return; } if (method.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == Roles.Condition) { invocationExpression.ReplaceWith(arguments[0]); return; } return; }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var method = invocationExpression.GetSymbol() as IMethod; if (method == null || !method.IsExtensionMethod || !invocationExpression.Arguments.Any()) { return; } IReadOnlyList <IType> typeArguments; MemberReferenceExpression memberRefExpr; switch (invocationExpression.Target) { case MemberReferenceExpression mre: typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = mre; break; case IdentifierExpression ide: typeArguments = ide.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = null; break; default: return; } var firstArgument = invocationExpression.Arguments.First(); if (firstArgument is NamedArgumentExpression) { return; } var target = firstArgument.GetResolveResult(); if (target is ConstantResolveResult crr && crr.ConstantValue == null) { target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion); } ResolveResult[] args = new ResolveResult[invocationExpression.Arguments.Count - 1]; string[] argNames = null; int pos = 0; foreach (var arg in invocationExpression.Arguments.Skip(1)) { if (arg is NamedArgumentExpression nae) { if (argNames == null) { argNames = new string[args.Length]; } argNames[pos] = nae.Name; args[pos] = nae.Expression.GetResolveResult(); } else { args[pos] = arg.GetResolveResult(); } pos++; } if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames)) { return; } if (firstArgument is NullReferenceExpression) { Debug.Assert(context.RequiredNamespacesSuperset.Contains(method.Parameters[0].Type.Namespace)); firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } if (invocationExpression.Target is IdentifierExpression identifierExpression) { identifierExpression.Detach(); memberRefExpr = new MemberReferenceExpression(firstArgument.Detach(), method.Name, identifierExpression.TypeArguments.Detach()); invocationExpression.Target = memberRefExpr; } else { memberRefExpr.Target = firstArgument.Detach(); } }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var method = invocationExpression.GetSymbol() as IMethod; if (method == null || !method.IsExtensionMethod || !invocationExpression.Arguments.Any()) { return; } IReadOnlyList <IType> typeArguments; MemberReferenceExpression memberRefExpr; switch (invocationExpression.Target) { case MemberReferenceExpression mre: typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = mre; break; case IdentifierExpression ide: typeArguments = ide.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = null; break; default: return; } var firstArgument = invocationExpression.Arguments.First(); if (firstArgument is NamedArgumentExpression) { return; } var target = firstArgument.GetResolveResult(); if (target is ConstantResolveResult crr && crr.ConstantValue == null) { target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion); } ResolveResult[] args = new ResolveResult[invocationExpression.Arguments.Count - 1]; string[] argNames = null; int pos = 0; foreach (var arg in invocationExpression.Arguments.Skip(1)) { if (arg is NamedArgumentExpression nae) { if (argNames == null) { argNames = new string[args.Length]; } argNames[pos] = nae.Name; args[pos] = nae.Expression.GetResolveResult(); } else { args[pos] = arg.GetResolveResult(); } pos++; } if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames)) { return; } if (firstArgument is DirectionExpression dirExpr) { if (!context.Settings.RefExtensionMethods || dirExpr.FieldDirection == FieldDirection.Out) { return; } firstArgument = dirExpr.Expression; target = firstArgument.GetResolveResult(); dirExpr.Detach(); } else if (firstArgument is NullReferenceExpression) { Debug.Assert(context.RequiredNamespacesSuperset.Contains(method.Parameters[0].Type.Namespace)); firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach())); } if (invocationExpression.Target is IdentifierExpression identifierExpression) { identifierExpression.Detach(); memberRefExpr = new MemberReferenceExpression(firstArgument.Detach(), method.Name, identifierExpression.TypeArguments.Detach()); invocationExpression.Target = memberRefExpr; } else { memberRefExpr.Target = firstArgument.Detach(); } if (invocationExpression.GetResolveResult() is CSharpInvocationResolveResult irr) { // do not forget to update the CSharpInvocationResolveResult => set IsExtensionMethodInvocation == true invocationExpression.RemoveAnnotations <CSharpInvocationResolveResult>(); var newResolveResult = new CSharpInvocationResolveResult( irr.TargetResult, irr.Member, irr.Arguments, irr.OverloadResolutionErrors, isExtensionMethodInvocation: true, irr.IsExpandedForm, irr.IsDelegateInvocation, irr.GetArgumentToParameterMap(), irr.InitializerStatements); invocationExpression.AddAnnotation(newResolveResult); } }
void ProcessInvocationExpression(InvocationExpression invocationExpression) { var method = invocationExpression.GetSymbol() as IMethod; if (method == null) { return; } var arguments = invocationExpression.Arguments.ToArray(); // Reduce "String.Concat(a, b)" to "a + b" if (method.Name == "Concat" && method.DeclaringType.FullName == "System.String" && CheckArgumentsForStringConcat(arguments)) { invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression Expression expr = arguments[0]; for (int i = 1; i < arguments.Length; i++) { expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); } expr.CopyAnnotationsFrom(invocationExpression); invocationExpression.ReplaceWith(expr); return; } switch (method.FullName) { case "System.Type.GetTypeFromHandle": if (arguments.Length == 1) { if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { Expression target = ((MemberReferenceExpression)arguments[0]).Target; target.CopyInstructionsFrom(invocationExpression); invocationExpression.ReplaceWith(target); return; } } break; case "System.Reflection.FieldInfo.GetFieldFromHandle": if (arguments.Length == 1) { MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression; if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation <LdTokenAnnotation>() != null) { invocationExpression.ReplaceWith(mre.Target); return; } } else if (arguments.Length == 2) { MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression; MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression; if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation <LdTokenAnnotation>() != null) { if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) { Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single(); FieldReference field = oldArg.Annotation <FieldReference>(); if (field != null) { AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach(); oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg)); invocationExpression.ReplaceWith(mre1.Target); return; } } } } break; case "System.Activator.CreateInstance": if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0])) { invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First()))); } break; case "System.String.Format": if (context.Settings.StringInterpolation && arguments.Length > 1 && arguments[0] is PrimitiveExpression stringExpression && stringExpression.Value is string && arguments.Skip(1).All(a => !a.DescendantsAndSelf.OfType <PrimitiveExpression>().Any(p => p.Value is string))) { var tokens = new List <(TokenKind, int, string)>(); int i = 0; foreach (var(kind, data) in TokenizeFormatString((string)stringExpression.Value)) { int index; switch (kind) { case TokenKind.Error: return; case TokenKind.String: tokens.Add((kind, -1, data)); break; case TokenKind.Argument: if (!int.TryParse(data, out index) || index != i) { return; } i++; tokens.Add((kind, index, null)); break; case TokenKind.ArgumentWithFormat: string[] arg = data.Split(new[] { ':' }, 2); if (arg.Length != 2 || arg[1].Length == 0) { return; } if (!int.TryParse(arg[0], out index) || index != i) { return; } i++; tokens.Add((kind, index, arg[1])); break;
static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, InvocationExpression invocationExpression, out MemberReferenceExpression memberRefExpr, out ResolveResult target, out Expression firstArgument) { var method = invocationExpression.GetSymbol() as IMethod; memberRefExpr = null; target = null; firstArgument = null; if (method == null || !method.IsExtensionMethod || !invocationExpression.Arguments.Any()) { return(false); } IReadOnlyList <IType> typeArguments; switch (invocationExpression.Target) { case MemberReferenceExpression mre: typeArguments = mre.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = mre; break; case IdentifierExpression ide: typeArguments = ide.TypeArguments.Any() ? method.TypeArguments : EmptyList <IType> .Instance; memberRefExpr = null; break; default: return(false); } firstArgument = invocationExpression.Arguments.First(); if (firstArgument is NamedArgumentExpression) { return(false); } target = firstArgument.GetResolveResult(); if (target is ConstantResolveResult crr && crr.ConstantValue == null) { target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion); } ResolveResult[] args = new ResolveResult[invocationExpression.Arguments.Count - 1]; string[] argNames = null; int pos = 0; foreach (var arg in invocationExpression.Arguments.Skip(1)) { if (arg is NamedArgumentExpression nae) { if (argNames == null) { argNames = new string[args.Length]; } argNames[pos] = nae.Name; args[pos] = nae.Expression.GetResolveResult(); } else { args[pos] = arg.GetResolveResult(); } pos++; } return(CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames)); }