diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/DiagnosticDescriptors.cs b/src/libraries/Microsoft.Extensions.Logging/gen/DiagnosticDescriptors.cs index 9e51646b52f17e..6f21ab335ad08f 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/DiagnosticDescriptors.cs +++ b/src/libraries/Microsoft.Extensions.Logging/gen/DiagnosticDescriptors.cs @@ -178,7 +178,7 @@ public static class DiagnosticDescriptors public static DiagnosticDescriptor MalformedFormatStrings { get; } = new DiagnosticDescriptor( id: "SYSLIB1022", - title: new LocalizableResourceString(nameof(SR.MalformedFormatStringsMessage), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), + title: new LocalizableResourceString(nameof(SR.MalformedFormatStringsTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), messageFormat: new LocalizableResourceString(nameof(SR.MalformedFormatStringsMessage), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), category: "LoggingGenerator", DiagnosticSeverity.Error, diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging/gen/LoggerMessageGenerator.Parser.cs index b7a7beea720edf..bdbd52299a17cc 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging/gen/LoggerMessageGenerator.Parser.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Text; namespace Microsoft.Extensions.Logging.Generators { @@ -195,6 +196,16 @@ public IReadOnlyList GetLogClasses(IEnumerable Can't have the same template with different casing + + Can't have malformed format strings (like dangling curly brackets, etc). + - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} Generating more than 6 arguments is not supported diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.cs.xlf index 044e1bd67633f0..5fec205d1fe434 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.cs.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.de.xlf index 258f697c492e26..60577db17a6ebc 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.de.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.es.xlf index 0424989915dd77..88ed4223b5469c 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.es.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.fr.xlf index a482372783f57c..4f5bfe5e16adf1 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.fr.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.it.xlf index 304056d1bd69fd..633af127a76ce8 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.it.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ja.xlf index c8b172fd7630b6..8c4c287602dcbd 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ja.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ko.xlf index fdb53576c829ad..7579833558cbfc 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ko.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pl.xlf index 790fec15f6a669..67dfd1d380b729 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pl.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pt-BR.xlf index 1451df01554bbe..bda8f7c746f27d 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.pt-BR.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ru.xlf index 66fbc83a6e6a94..abf0c6bcebe273 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.ru.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.tr.xlf index fc70ba858ab992..a3a06c272f0f02 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.tr.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hans.xlf index 2cdeaa1133a21c..c97c06606a3206 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hant.xlf index 52f65573cda1e2..0ae39cdac3c2b7 100644 --- a/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Logging/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -63,8 +63,13 @@ - Can't have malformed format strings (like dangling {, etc) - Can't have malformed format strings (like dangling {, etc) + Can't have malformed format strings (like dangling curly brackets, etc). {0} + Can't have malformed format strings (like dangling curly brackets, etc). {0} + + + + Can't have malformed format strings (like dangling curly brackets, etc). + Can't have malformed format strings (like dangling curly brackets, etc). diff --git a/src/libraries/Microsoft.Extensions.Logging/gen/TemplateHelper.cs b/src/libraries/Microsoft.Extensions.Logging/gen/TemplateHelper.cs new file mode 100644 index 00000000000000..d05074e698e753 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging/gen/TemplateHelper.cs @@ -0,0 +1,346 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Text +{ + internal static class TemplateHelper + { + /// + /// Parses the message template and throws exception for malformed messages. + /// + internal static string Parse(this string msg, List? templates) + { + ReadOnlySpan format = msg.AsSpan(); + var builder = new StringBuilder(msg.Length); + var pos = 0; + var len = format.Length; + var ch = '\0'; + var segments = new List(); + var numArgs = 0; + + while (true) + { + var segStart = builder.Length; + while (pos < len) + { + ch = format[pos]; + + pos++; + if (ch == '}') + { + if (pos < len && format[pos] == '}') + { + // double }, treat as escape sequence + pos++; + } + else + { + // dangling }, fail + throw new ArgumentException($"Dangling }} in format string at position {pos}", nameof(format)); + } + } + else if (ch == '{') + { + if (pos < len && format[pos] == '{') + { + // double {, treat as escape sequence + pos++; + } + else + { + // start of a format specification + pos--; + break; + } + } + + builder.Append(ch); + } + + if (pos == len) + { + var totalLit = builder.Length - segStart; + while (totalLit > 0) + { + var num = totalLit; + if (num > short.MaxValue) + { + num = short.MaxValue; + } + + segments.Add(new Segment((short)num, -1, 0, string.Empty)); + totalLit -= num; + } + + return builder.ToString(); + } + + // extract the argument index + var argIndex = 0; + if (templates == null) + { + // classic composite format string + + pos++; + if (pos == len || (ch = format[pos]) < '0' || ch > '9') + { + // we need an argument index + throw new ArgumentException($"Missing argument index in format string at position {pos}", nameof(format)); + } + + do + { + argIndex = (argIndex * 10) + (ch - '0'); + pos++; + + // make sure we get a suitable end to the argument index + if (pos == len) + { + throw new ArgumentException($"Invalid argument index in format string at position {pos}", nameof(format)); + } + + ch = format[pos]; + } + while (ch >= '0' && ch <= '9'); + } + else + { + // template-based format string + + pos++; + if (pos == len) + { + // we need a template name + throw new ArgumentException($"Missing template name in format string at position {pos}", nameof(format)); + } + + ch = format[pos]; + if (!ValidTemplateNameChar(ch, true)) + { + // we need a template name + throw new ArgumentException($"Missing template name in format string at position {pos}", nameof(format)); + } + + // extract the template name + var start = pos; + do + { + pos++; + + // make sure we get a suitable end + if (pos == len) + { + throw new ArgumentException($"Invalid template name in format string at position {pos}", nameof(format)); + } + + ch = format[pos]; + } + while (ValidTemplateNameChar(ch, false)); + + // get an argument index for the given template + var template = format.Slice(start, pos - start).ToString(); + argIndex = templates.IndexOf(template); + if (argIndex < 0) + { + templates.Add(template); + argIndex = numArgs; + } + } + + if (argIndex >= numArgs) + { + // new max arg count + numArgs = argIndex + 1; + } + + // skip whitespace + while (pos < len && (ch = format[pos]) == ' ') + { + pos++; + } + + // parse the optional field width + var leftAligned = false; + var argWidth = 0; + if (ch == ',') + { + pos++; + + // skip whitespace + while (pos < len && format[pos] == ' ') + { + pos++; + } + + // did we run out of steam + if (pos == len) + { + throw new ArgumentException($"Invalid field width for argument {numArgs + 1} in format string", nameof(format)); + } + + ch = format[pos]; + if (ch == '-') + { + leftAligned = true; + pos++; + + // did we run out of steam? + if (pos == len) + { + throw new ArgumentException($"Invalid field width for argument {numArgs + 1} in format string", nameof(format)); + } + + ch = format[pos]; + } + + if (ch < '0' || ch > '9') + { + throw new ArgumentException($"Invalid character in field width for argument {numArgs + 1} in format string", nameof(format)); + } + + var val = 0; + do + { + val = (val * 10) + (ch - '0'); + pos++; + + // did we run out of steam? + if (pos == len) + { + throw new ArgumentException($"Incomplete field width at position {pos}", nameof(format)); + } + + // did we get a number that's too big? + if (val > short.MaxValue) + { + throw new ArgumentException($"Field width value exceeds limit for argument {numArgs + 1} in format string", nameof(format)); + } + + ch = format[pos]; + } + while (ch >= '0' && ch <= '9'); + + argWidth = val; + } + + if (leftAligned) + { + argWidth = -argWidth; + } + + // skip whitespace + while (pos < len && (ch = format[pos]) == ' ') + { + pos++; + } + + // parse the optional argument format string + + var argFormat = string.Empty; + if (ch == ':') + { + pos++; + var argFormatStart = pos; + + while (true) + { + if (pos == len) + { + throw new ArgumentException($"Unterminated format specification at position {pos}", nameof(format)); + } + + ch = format[pos]; + pos++; + if (ch == '{') + { + throw new ArgumentException($"Nested {{ in format specification at position {pos}", nameof(format)); + } + else if (ch == '}') + { + // end of format specification + pos--; + break; + } + } + + if (pos != argFormatStart) + { + argFormat = format.Slice(argFormatStart, pos - argFormatStart).ToString(); + } + } + + if (ch != '}') + { + throw new ArgumentException("Unterminated format specification", nameof(format)); + } + + // skip over the closing brace + pos++; + + if (numArgs >= short.MaxValue) + { + throw new ArgumentException("Must have less than 32768 arguments", nameof(format)); + } + + var total = builder.Length - segStart; + while (total > short.MaxValue) + { + segments.Add(new Segment(short.MaxValue, -1, 0, string.Empty)); + total -= short.MaxValue; + } + + segments.Add(new Segment((short)total, (short)argIndex, (short)argWidth, argFormat)); + } + } + + private static bool ValidTemplateNameChar(char ch, bool first) + { + if (first) + { + return char.IsLetter(ch) || ch == '_'; + } + + return char.IsLetterOrDigit(ch) || ch == '_'; + } + + /// + /// A chunk of formatting information. + /// + private readonly struct Segment + { + public Segment(short literalCount, short argIndex, short argWidth, string argFormat) + { + LiteralCount = literalCount; + ArgIndex = argIndex; + ArgWidth = argWidth; + ArgFormat = argFormat; + } + + /// + /// Gets the number of chars of literal text consumed by this segment. + /// + public short LiteralCount { get; } + + /// + /// Gets the index of the argument to be formatted, -1 to skip argument formatting. + /// + public short ArgIndex { get; } + + /// + /// Gets the width of the formatted value in characters. If this is negative, it indicates to left-justify + /// and the field width is then the absolute value. + /// + public short ArgWidth { get; } + + /// + /// Gets the custom format string to use when formatting the argument. + /// + public string ArgFormat { get; } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Logging/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index f8942e11b6140b..a59caddd55ef8b 100644 --- a/src/libraries/Microsoft.Extensions.Logging/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -214,23 +214,23 @@ partial class C Assert.Single(diagnostics); Assert.Equal(DiagnosticDescriptors.InconsistentTemplateCasing.Id, diagnostics[0].Id); } +#endif - // TODO: can't have malformed format strings (like dangling {, etc) - [Fact] - public async Task MalformedFormatString() + [Theory] + [MemberData(nameof(BadlyFormattedLogMethodTestData))] + public async Task TemplatesWithMalformedFormatString(string badlyFormattedLogMethod, string expectedMessageSegment) { - IReadOnlyList diagnostics = await RunGenerator(@" + IReadOnlyList diagnostics = await RunGenerator($@" partial class C - { - [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1 {p1} {P1}"")] - static partial void M1(ILogger logger, int p1, int P1); - } + {{ + {badlyFormattedLogMethod} + }} "); Assert.Single(diagnostics); Assert.Equal(DiagnosticDescriptors.MalformedFormatStrings.Id, diagnostics[0].Id); + Assert.Contains(expectedMessageSegment, diagnostics[0].GetMessage(), StringComparison.InvariantCulture); } -#endif [Fact] public async Task InvalidParameterName() @@ -488,18 +488,6 @@ partial class C [LoggerMessage(EventId = 2, Level = LogLevel.Debug, Message = ""M2 {arg1} {arg2}"")] static partial void M2(ILogger logger, string arg1, string arg2); - [LoggerMessage(EventId = 3, Level = LogLevel.Debug, Message = ""M3 {arg1"")] - static partial void M3(ILogger logger); - - [LoggerMessage(EventId = 4, Level = LogLevel.Debug, Message = ""M4 arg1}"")] - static partial void M4(ILogger logger); - - [LoggerMessage(EventId = 5, Level = LogLevel.Debug, Message = ""M5 {"")] - static partial void M5(ILogger logger); - - [LoggerMessage(EventId = 6, Level = LogLevel.Debug, Message = ""}M6 "")] - static partial void M6(ILogger logger); - [LoggerMessage(EventId = 7, Level = LogLevel.Debug, Message = ""M7 {{arg1}}"")] static partial void M7(ILogger logger); } @@ -590,5 +578,31 @@ private static async Task> RunGenerator( return d; } + + public static IEnumerable BadlyFormattedLogMethodTestData + { + get + { + yield return new object[] { @" + [LoggerMessage(EventId = 3, Level = LogLevel.Debug, Message = ""M3 {arg1"")] + static partial void M3(ILogger logger);", + "Invalid template name in format string at position" }; + + yield return new object[] { @" + [LoggerMessage(EventId = 4, Level = LogLevel.Debug, Message = ""M4 arg1}"")] + static partial void M4(ILogger logger);", + "Dangling } in format string at position" }; + + yield return new object[] { @" + [LoggerMessage(EventId = 5, Level = LogLevel.Debug, Message = ""M5 {"")] + static partial void M5(ILogger logger);", + "Missing template name in format string at position" }; + + yield return new object[] { @" + [LoggerMessage(EventId = 6, Level = LogLevel.Debug, Message = ""}M6 "")] + static partial void M6(ILogger logger);", + "Dangling } in format string at position" }; + } + } } }