diff --git a/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs b/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs index af887d2731..feb4aaf3aa 100644 --- a/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs +++ b/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs @@ -303,6 +303,29 @@ namespace ICSharpCode.NRefactory.Utils var errors = SegmentTest(1, segments.First()); ErrorTest(errors[0], " Some text 55", "0", 3, 16); } + + [Test] + public void MissingEndBraceInsideFixedText() + { + var segments = ParseTest("Text {0 Text", + new TextSegment("Text "), + new FormatItem(0) { StartLocation = 5, EndLocation = 7 }, + new TextSegment(" Text", 7)); + var errors = SegmentTest(1, segments.Skip(1).First()); + ErrorTest(errors[0], "", "}", 7, 7); + } + + [Test] + public void MissingEndBraceInsideFixedTextEndingInAnotherFormatItem() + { + var segments = ParseTest("Text {0 Text {1}", + new TextSegment("Text "), + new FormatItem(0) { StartLocation = 5, EndLocation = 7 }, + new TextSegment(" Text ", 7), + new FormatItem(1) { StartLocation = 13, EndLocation = 16 }); + var errors = SegmentTest(1, segments.Skip(1).First()); + ErrorTest(errors[0], "", "}", 7, 7); + } } } diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs index bd3fc38f76..d4de9d12a4 100644 --- a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs @@ -108,6 +108,10 @@ namespace ICSharpCode.NRefactory.Utils argumentFormat = ParseSubFormatString(format, ref i, length); CheckForMissingEndBrace (format, i, length); + // Handle unclosed format items in the middle of fixed text + if (i < length && format[i] != '}') + --i; + // i may actually point outside of format; if that happens, we want the last position var endLocation = Math.Min (length, i + 1); var errors = GetErrors (); @@ -209,11 +213,14 @@ namespace ICSharpCode.NRefactory.Utils return; } - string GetUntil (string format, string delimiters, ref int index) + string GetText (string format, string delimiters, ref int index) { int start = index; - while (index < format.Length && !delimiters.Contains(format[index].ToString())) + while (index < format.Length && !delimiters.Contains(format[index].ToString())) { + if (format[index] == '{' && (index + 1 < format.Length && format[index + 1] != '{')) + break; ++index; + } return format.Substring (start, index - start); } @@ -240,16 +247,28 @@ namespace ICSharpCode.NRefactory.Utils return positive ? sum : -sum; } - int? GetAndCheckNumber(string format, string delimiters, ref int index, int numberFieldStart, out int parsedCharacters) + int? GetAndCheckNumber (string format, string delimiters, ref int index, int numberFieldStart, out int parsedCharacters) { - var numberText = GetUntil(format, delimiters, ref index); + int fieldIndex = index; + var numberText = GetText (format, delimiters, ref fieldIndex); + int fieldEnd = fieldIndex; parsedCharacters = numberText.Length; - int digitCount = 0; - int? number = GetNumber(numberText, ref digitCount); - if (digitCount != parsedCharacters) { + int numberLength = 0; + int? number = GetNumber (numberText, ref numberLength); + var endingChar = index + numberLength; + if (numberLength != parsedCharacters && fieldEnd < format.Length && delimiters.Contains (format [fieldEnd])) { // Not the entire number field could be parsed + // The field actually ended as intended, so set the index to the end of the field + index = fieldEnd; var suggestedNumber = (number ?? 0).ToString (); - AddInvalidNumberFormatError(numberFieldStart, format.Substring(numberFieldStart, index - numberFieldStart), suggestedNumber); + AddInvalidNumberFormatError (numberFieldStart, format.Substring (numberFieldStart, index - numberFieldStart), suggestedNumber); + } else if (numberLength != parsedCharacters) { + // Not the entire number field could be parsed + // The field didn't end, it was cut off so we are missing an ending brace + index = endingChar; + AddMissingEndBraceError (index, index, "Missing ending '}'", ""); + } else { + index = endingChar; } return number; }