Esempio n. 1
0
        private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSyntax node, BindingDiagnosticBag diagnostics)
        {
            var builder = ArrayBuilder <BoundExpression> .GetInstance();

            var           stringType       = GetSpecialType(SpecialType.System_String, diagnostics, node);
            ConstantValue?resultConstant   = null;
            bool          isResultConstant = true;

            if (node.Contents.Count == 0)
            {
                resultConstant = ConstantValue.Create(string.Empty);
            }
            else
            {
                var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
                var intType    = GetSpecialType(SpecialType.System_Int32, diagnostics, node);
                foreach (var content in node.Contents)
                {
                    switch (content.Kind())
                    {
                    case SyntaxKind.Interpolation:
                    {
                        var interpolation = (InterpolationSyntax)content;
                        var value         = BindValue(interpolation.Expression, diagnostics, BindValueKind.RValue);
                        if (value.Type is null)
                        {
                            value = GenerateConversionForAssignment(objectType, value, diagnostics);
                        }
                        else
                        {
                            value = BindToNaturalType(value, diagnostics);
                            _     = GenerateConversionForAssignment(objectType, value, diagnostics);
                        }

                        // We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering,
                        // when we perform overload resolution, to report a problem. So we do that check by calling
                        // GenerateConversionForAssignment with objectType. However we want to preserve the original expression's
                        // natural type so that overload resolution may select a specialized implementation of string.Format,
                        // so we discard the result of that call and only preserve its diagnostics.
                        BoundExpression?alignment = null;
                        BoundLiteral?   format    = null;
                        if (interpolation.AlignmentClause != null)
                        {
                            alignment = GenerateConversionForAssignment(intType, BindValue(interpolation.AlignmentClause.Value, diagnostics, Binder.BindValueKind.RValue), diagnostics);
                            var alignmentConstant = alignment.ConstantValue;
                            if (alignmentConstant != null && !alignmentConstant.IsBad)
                            {
                                const int magnitudeLimit = 32767;
                                // check that the magnitude of the alignment is "in range".
                                int alignmentValue = alignmentConstant.Int32Value;
                                //  We do the arithmetic using negative numbers because the largest negative int has no corresponding positive (absolute) value.
                                alignmentValue = (alignmentValue > 0) ? -alignmentValue : alignmentValue;
                                if (alignmentValue < -magnitudeLimit)
                                {
                                    diagnostics.Add(ErrorCode.WRN_AlignmentMagnitude, alignment.Syntax.Location, alignmentConstant.Int32Value, magnitudeLimit);
                                }
                            }
                            else if (!alignment.HasErrors)
                            {
                                diagnostics.Add(ErrorCode.ERR_ConstantExpected, interpolation.AlignmentClause.Value.Location);
                            }
                        }

                        if (interpolation.FormatClause != null)
                        {
                            var  text = interpolation.FormatClause.FormatStringToken.ValueText;
                            char lastChar;
                            bool hasErrors = false;
                            if (text.Length == 0)
                            {
                                diagnostics.Add(ErrorCode.ERR_EmptyFormatSpecifier, interpolation.FormatClause.Location);
                                hasErrors = true;
                            }
                            else if (SyntaxFacts.IsWhitespace(lastChar = text[text.Length - 1]) || SyntaxFacts.IsNewLine(lastChar))
                            {
                                diagnostics.Add(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, interpolation.FormatClause.Location);
                                hasErrors = true;
                            }

                            format = new BoundLiteral(interpolation.FormatClause, ConstantValue.Create(text), stringType, hasErrors);
                        }

                        builder.Add(new BoundStringInsert(interpolation, value, alignment, format, null));
                        if (!isResultConstant ||
                            value.ConstantValue == null ||
                            !(interpolation is { FormatClause: null, AlignmentClause: null }) ||
                            !(value.ConstantValue is { IsString: true, IsBad: false }))