Verify arguments length for diagnostic messages#60925
Conversation
| } | ||
|
|
||
| [Conditional("DEBUG")] | ||
| internal static void AssertExpectedMessageArgumentsLength(CommonMessageProvider messageProvider, int errorCode, int actualLength) |
There was a problem hiding this comment.
Is this path for compiler diagnostics only?
I think it would be beneficial to have the assert for all diagnostics (to prevent IDExxxx from having bugs too)
Then the following analyzer will need to be excluded:
roslyn/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs
Lines 894 to 914 in 8defa4a
Not sure if that makes sense? #Resolved
There was a problem hiding this comment.
I've limited the change to C# compiler diagnostics for now, to keep the scope manageable. We can consider addressing other diagnostics, separately, as needed.
There was a problem hiding this comment.
I think it would be beneficial to have the assert for all diagnostics (to prevent IDExxxx from having bugs too)
I have no objection, as long as this is a debug-only assertion. It's possible we have runtime scenarios where the diagnostic intentionally provides more placeholders than are used by the message.
| if (errorCode <= 0) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
When can this happen?
#Resolved
There was a problem hiding this comment.
For ErrorCode.Void and ErrorCode.Unknown which are used as placeholders for errors.
| { | ||
| return; | ||
| } | ||
| string message = messageProvider.LoadMessage(errorCode, language: null) ?? string.Empty; |
There was a problem hiding this comment.
Can LoadMessage return null for a reason other than a bug? #Resolved
| { | ||
| expectedLength = Math.Max(int.Parse(match.Value[1..^1]) + 1, expectedLength); | ||
| } | ||
| Debug.Assert(expectedLength == actualLength); |
There was a problem hiding this comment.
Would Debug.Assert(expectedLength == matches.Count) be valid (in addition to the existing assert)? #Resolved
There was a problem hiding this comment.
matches has entries for each argument use, even duplicates, so matches.Count may not equal expectedLength. But it makes sense to check that all arguments are used, so I've used a BitVector instead, thanks.
There is one resource string that fails this new check: ERR_IdentifierExpectedKW. I've disabled the check for that ErrorCode, rather than changing the resource string and the arguments array, to avoid breaking translated resources. The assert is useful for new cases where arguments are unused though.
| [Conditional("DEBUG")] | ||
| internal static void AssertExpectedMessageArgumentsLength(CommonMessageProvider messageProvider, int errorCode, int actualLength) | ||
| { | ||
| #if DEBUG |
There was a problem hiding this comment.
It's not strictly necessary but it seemed reasonable to avoid emitting the method body in release builds.
| return TypeWithAnnotations.Create(new ExtendedErrorTypeSymbol( | ||
| Compilation.Assembly.GlobalNamespace, identifierValueText, 0, | ||
| new CSDiagnosticInfo(ErrorCode.ERR_SingleTypeNameNotFound))); | ||
| new CSDiagnosticInfo(ErrorCode.ERR_SingleTypeNameNotFound, identifierValueText))); |
There was a problem hiding this comment.
Which test failed this?
I think this change fixes #59417 but how can we observe that through a test?
There was a problem hiding this comment.
There were a number of tests that failed, including IOperationTests_IConversionExpression.ConversionExpression_Implicit_ReferenceConversion_InvalidSyntax and IOperationTests_ISizeOfExpression.TestSizeOfExpression_MissingArgument. The DiagnosticInfo is used in the resulting ExtendedErrorTypeSymbol but it's not clear how to construct a test where the ExtendedErrorTypeSymbol.ErrorInfo is reported from such cases though.
5184fb4 to
5a6a9aa
Compare
| 0 => false, | ||
| ErrorCode.Unknown => false, | ||
| ErrorCode.Void => false, | ||
| ErrorCode.WRN_XMLParseError => false, // should investigate failures here |
There was a problem hiding this comment.
Investigated and added comment here.
| int expectedLength = 0; | ||
| foreach (object? m in matches) | ||
| { | ||
| if (m is Match { } match) |
jcouv
left a comment
There was a problem hiding this comment.
LGTM Thanks (iteration 7) with a couple of nits to consider
Verify
DiagnosticInfo()arguments array length matches the expected value from the diagnostic message (C# only).Fixes #60862 for C#.