提交 d6ae8dce 编写于 作者: N nslottow

Modified C# directive parser to allow #pragma warning disable/restore to take...

Modified C# directive parser to allow #pragma warning disable/restore to take string IDs in addition to integers in order to generalize to user-generated diagnostics. Compiler-generated diagnostics all have integer error codes in addition to a string ID, but user-generated diagnostics are only identified by a string ID. This change also affects the language grammar, effectively changing the grammar of "warning-list" in section 2.5.8.1 of the C# spec from:

warning-list:
    decimal-digits
    warning-list   whitespaceopt   ,   whitespaceopt   decimal-digits

to:

warning-id:
    decimal-digits
    string-literal

warning-list:
    warning-id
    warning-list   whitespaceopt   ,   whitespaceopt   warning-id

As implemented, the compiler will accept the following:

#pragma warning disable ?CS0168?
#pragma warning disable ?CS0168?, ?CS0219?
#pragma warning disable ?CS0168?, 219 // , ... etc.

And warn about the following:

#pragma warning disable ?CS168? // warning CS1691: 'CS168' is not a valid warning number
#pragma warning disable 1 // warning CS1691: ?1? is not a valid warning number (current behavior)

Only strings that match 'CS[0-9]*' are assumed to be compiler diagnostic IDs, so the compiler will not warn about something like:

#pragma warning disable "CS1MyWarning" // This could be a user diagnostic ID (changeset 1209083)
上级 a2fee14e
...@@ -10599,6 +10599,15 @@ internal class CSharpResources { ...@@ -10599,6 +10599,15 @@ internal class CSharpResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to String or numeric literal expected.
/// </summary>
internal static string WRN_StringOrNumericLiteralExpected {
get {
return ResourceManager.GetString("WRN_StringOrNumericLiteralExpected", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Source file has exceeded the limit of 16,707,565 lines representable in the PDB; debug information will be incorrect. /// Looks up a localized string similar to Source file has exceeded the limit of 16,707,565 lines representable in the PDB; debug information will be incorrect.
/// </summary> /// </summary>
......
...@@ -3779,4 +3779,7 @@ ...@@ -3779,4 +3779,7 @@
<data name="OperationCausedStackOverflow" xml:space="preserve"> <data name="OperationCausedStackOverflow" xml:space="preserve">
<value>Operation caused a stack overflow.</value> <value>Operation caused a stack overflow.</value>
</data> </data>
<data name="WRN_StringOrNumericLiteralExpected" xml:space="preserve">
<value>String or numeric literal expected</value>
</data>
</root> </root>
\ No newline at end of file
...@@ -644,6 +644,7 @@ internal enum ErrorCode ...@@ -644,6 +644,7 @@ internal enum ErrorCode
ERR_DottedTypeNameNotFoundInNSFwd = 1069, ERR_DottedTypeNameNotFoundInNSFwd = 1069,
ERR_SingleTypeNameNotFoundFwd = 1070, ERR_SingleTypeNameNotFoundFwd = 1070,
//ERR_NoSuchMemberOnNoPIAType = 1071, //EE //ERR_NoSuchMemberOnNoPIAType = 1071, //EE
WRN_StringOrNumericLiteralExpected = 1072,
// ERR_EOLExpected = 1099, // EE // ERR_EOLExpected = 1099, // EE
// ERR_NotSupportedinEE = 1100, // EE // ERR_NotSupportedinEE = 1100, // EE
ERR_BadThisParam = 1100, ERR_BadThisParam = 1100,
......
...@@ -276,6 +276,7 @@ internal static int GetWarningLevel(ErrorCode code) ...@@ -276,6 +276,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_RefCultureMismatch: case ErrorCode.WRN_RefCultureMismatch:
case ErrorCode.WRN_ConflictingMachineAssembly: case ErrorCode.WRN_ConflictingMachineAssembly:
case ErrorCode.WRN_FilterIsConstant: case ErrorCode.WRN_FilterIsConstant:
case ErrorCode.WRN_StringOrNumericLiteralExpected:
return 1; return 1;
default: default:
return 0; return 0;
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq; using System.Linq;
...@@ -374,32 +374,65 @@ private DirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, SyntaxToken ...@@ -374,32 +374,65 @@ private DirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, SyntaxToken
if (this.CurrentToken.Kind == SyntaxKind.DisableKeyword || this.CurrentToken.Kind == SyntaxKind.RestoreKeyword) if (this.CurrentToken.Kind == SyntaxKind.DisableKeyword || this.CurrentToken.Kind == SyntaxKind.RestoreKeyword)
{ {
style = this.EatToken(); style = this.EatToken();
var codes = new SeparatedSyntaxListBuilder<ExpressionSyntax>(10); var ids = new SeparatedSyntaxListBuilder<ExpressionSyntax>(10);
while (this.CurrentToken.Kind != SyntaxKind.EndOfDirectiveToken) while (this.CurrentToken.Kind != SyntaxKind.EndOfDirectiveToken)
{ {
var code = this.EatToken(SyntaxKind.NumericLiteralToken, ErrorCode.WRN_InvalidNumber, reportError: isActive); SyntaxToken id;
if (isActive && !code.IsMissing) ExpressionSyntax idExpression;
if (this.CurrentToken.Kind == SyntaxKind.NumericLiteralToken || this.CurrentToken.Kind == SyntaxKind.StringLiteralToken)
{ {
int value = (int)code.Value; id = this.EatToken();
if (ErrorFacts.GetSeverity((ErrorCode)value) != DiagnosticSeverity.Warning) if (isActive)
{ {
code = this.AddError(code, ErrorCode.WRN_BadWarningNumber, value); if (id.Kind == SyntaxKind.NumericLiteralToken)
{
int compilerWarningNumber = (int)id.Value;
if (ErrorFacts.GetSeverity((ErrorCode)compilerWarningNumber) != DiagnosticSeverity.Warning)
{
id = this.AddError(id, ErrorCode.WRN_BadWarningNumber, compilerWarningNumber);
}
}
else
{
string value = (string)id.Value;
var messageProvider = MessageProvider.Instance;
if (value.StartsWith(messageProvider.CodePrefix))
{
// For diagnostic IDs of the form "CS[0-9]*", verify the error code is that of a warning
int compilerWarningNumber;
if (int.TryParse(value.Substring(messageProvider.CodePrefix.Length), out compilerWarningNumber) &&
(messageProvider.GetIdForErrorCode(compilerWarningNumber) != value ||
ErrorFacts.GetSeverity((ErrorCode)compilerWarningNumber) != DiagnosticSeverity.Warning))
{
id = this.AddError(id, ErrorCode.WRN_BadWarningNumber, value);
}
}
}
} }
var expressionKind = id.Kind == SyntaxKind.NumericLiteralToken ? SyntaxKind.NumericLiteralExpression : SyntaxKind.StringLiteralExpression;
idExpression = SyntaxFactory.LiteralExpression(expressionKind, id);
}
else
{
id = this.EatToken(SyntaxKind.NumericLiteralToken, ErrorCode.WRN_StringOrNumericLiteralExpected, reportError: isActive);
idExpression = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, id);
} }
hasError = hasError || code.ContainsDiagnostics; hasError = hasError || id.ContainsDiagnostics;
codes.Add(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, code)); ids.Add(idExpression);
if (this.CurrentToken.Kind != SyntaxKind.CommaToken) if (this.CurrentToken.Kind != SyntaxKind.CommaToken)
{ {
break; break;
} }
codes.AddSeparator(this.EatToken()); ids.AddSeparator(this.EatToken());
} }
var end = this.ParseEndOfDirective(hasError || !isActive, afterPragma: true); var end = this.ParseEndOfDirective(hasError || !isActive, afterPragma: true);
return SyntaxFactory.PragmaWarningDirectiveTrivia(hash, pragma, warning, style, codes.ToList(), end, isActive); return SyntaxFactory.PragmaWarningDirectiveTrivia(hash, pragma, warning, style, ids.ToList(), end, isActive);
} }
else else
{ {
......
...@@ -96,8 +96,10 @@ private static WarningStateMapEntry[] CreatePragmaWarningStateEntries(ImmutableA ...@@ -96,8 +96,10 @@ private static WarningStateMapEntry[] CreatePragmaWarningStateEntries(ImmutableA
if (currentDirective.ErrorCodes[x].IsMissing || currentDirective.ErrorCodes[x].ContainsDiagnostics) if (currentDirective.ErrorCodes[x].IsMissing || currentDirective.ErrorCodes[x].ContainsDiagnostics)
continue; continue;
int errorCode = (int)((LiteralExpressionSyntax)currentDirective.ErrorCodes[x]).Token.Value; var token = ((LiteralExpressionSyntax)currentDirective.ErrorCodes[x]).Token;
string errorId = MessageProvider.Instance.GetIdForErrorCode(errorCode); string errorId = token.CSharpKind() == SyntaxKind.NumericLiteralToken ?
MessageProvider.Instance.GetIdForErrorCode((int)token.Value) :
(string)token.Value;
// Update the state of this error code with the current directive state // Update the state of this error code with the current directive state
accumulatedSpecificWarningState = accumulatedSpecificWarningState.SetItem(errorId, directiveState); accumulatedSpecificWarningState = accumulatedSpecificWarningState.SetItem(errorId, directiveState);
......
...@@ -92,7 +92,7 @@ class C { } ...@@ -92,7 +92,7 @@ class C { }
ParserErrorMessageTests.ParseAndValidate(source, ParserErrorMessageTests.ParseAndValidate(source,
Diagnostic(ErrorCode.WRN_IllegalPragma, ""), Diagnostic(ErrorCode.WRN_IllegalPragma, ""),
Diagnostic(ErrorCode.WRN_IllegalPPWarning, ""), Diagnostic(ErrorCode.WRN_IllegalPPWarning, ""),
Diagnostic(ErrorCode.WRN_InvalidNumber, "foo"), Diagnostic(ErrorCode.WRN_StringOrNumericLiteralExpected, "foo"),
Diagnostic(ErrorCode.WRN_BadWarningNumber, "0").WithArguments("0"), Diagnostic(ErrorCode.WRN_BadWarningNumber, "0").WithArguments("0"),
Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""), Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""),
Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""), Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""),
......
...@@ -45,7 +45,7 @@ internal struct PragmaInfo ...@@ -45,7 +45,7 @@ internal struct PragmaInfo
public SyntaxKind PragmaKind; public SyntaxKind PragmaKind;
public SyntaxKind WarningOrChecksumKind; public SyntaxKind WarningOrChecksumKind;
public SyntaxKind DisableOrRestoreKind; public SyntaxKind DisableOrRestoreKind;
public int[] WarnginList; public int[] WarningList;
public string[] FileGuidByte; public string[] FileGuidByte;
} }
...@@ -248,23 +248,34 @@ private void VerifyDirectivePragma(CSharpSyntaxNode node, PragmaInfo expected) ...@@ -248,23 +248,34 @@ private void VerifyDirectivePragma(CSharpSyntaxNode node, PragmaInfo expected)
Assert.Equal(expected.DisableOrRestoreKind, pwd.DisableOrRestoreKeyword.CSharpKind()); Assert.Equal(expected.DisableOrRestoreKind, pwd.DisableOrRestoreKeyword.CSharpKind());
} }
if (expected.WarnginList == null || expected.WarnginList.Length == 0) if (expected.WarningList == null || expected.WarningList.Length == 0)
{ {
Assert.Equal(0, pwd.ErrorCodes.Count); Assert.Equal(0, pwd.ErrorCodes.Count);
} }
else else
{ {
Assert.Equal(expected.WarnginList.Length, pwd.ErrorCodes.Count); Assert.Equal(expected.WarningList.Length, pwd.ErrorCodes.Count);
int idx = 0; int idx = 0;
foreach (var w in expected.WarnginList) foreach (var warningNumber in expected.WarningList)
{ {
var wc = ((LiteralExpressionSyntax)pwd.ErrorCodes[idx++]).Token; var token = ((LiteralExpressionSyntax)pwd.ErrorCodes[idx++]).Token;
// not check if <=0 if (warningNumber > 0)
if (w > 0)
{ {
Assert.Equal(w, wc.Value); var tokenKind = token.CSharpKind();
Assert.Equal(w, Int32.Parse(wc.Text)); if (tokenKind == SyntaxKind.NumericLiteralToken)
{
Assert.Equal(warningNumber, token.Value);
Assert.Equal(warningNumber, int.Parse(token.Text));
}
else if (tokenKind == SyntaxKind.StringLiteralToken)
{
Assert.Equal(MessageProvider.Instance.GetIdForErrorCode(warningNumber), token.Value);
}
else
{
Assert.True(false, "Warning ID must be a string or numeric literal");
}
} }
} }
} }
...@@ -3291,7 +3302,7 @@ public void TestPragmaWarningDisable() ...@@ -3291,7 +3302,7 @@ public void TestPragmaWarningDisable()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword, DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 114 } WarningList = new int[] { 114 }
}); });
} }
...@@ -3307,7 +3318,7 @@ public void TestPragmaWarningDisableWithMultipleCodes() ...@@ -3307,7 +3318,7 @@ public void TestPragmaWarningDisableWithMultipleCodes()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword, DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 114, 162, 168 } WarningList = new int[] { 114, 162, 168 }
}); });
} }
...@@ -3335,7 +3346,7 @@ class A ...@@ -3335,7 +3346,7 @@ class A
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword, DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 440 } WarningList = new int[] { 440 }
}); });
// verify that GetParseDiagnostics filters disabled warning // verify that GetParseDiagnostics filters disabled warning
...@@ -3361,7 +3372,7 @@ public void TestRegressNegPragmaWarningDisableWithBadCode() ...@@ -3361,7 +3372,7 @@ public void TestRegressNegPragmaWarningDisableWithBadCode()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword, DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 99999 } WarningList = new int[] { 99999 }
}); });
} }
...@@ -3377,7 +3388,7 @@ public void TestPragmaWarningRestore() ...@@ -3377,7 +3388,7 @@ public void TestPragmaWarningRestore()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.RestoreKeyword, DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
WarnginList = new int[] { 114 } WarningList = new int[] { 114 }
}); });
} }
...@@ -3393,7 +3404,23 @@ public void TestPragmaWarningRestoreWithMultipleCodes() ...@@ -3393,7 +3404,23 @@ public void TestPragmaWarningRestoreWithMultipleCodes()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.RestoreKeyword, DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
WarnginList = new int[] { 114, 162, 168 } WarningList = new int[] { 114, 162, 168 }
});
}
[Fact]
[Trait("Feature", "Directives")]
public void TestPragmaWarningRestoreWithMixedStringAndNumericCodes()
{
var text = @"#pragma warning restore ""CS0114"", 162, ""CS0168"" // Mixed string & numeric codes";
var node = Parse(text);
TestRoundTripping(node, text);
VerifyDirectivePragma(node, new PragmaInfo
{
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
WarningList = new int[] { 114, 162, 168 }
}); });
} }
...@@ -3404,13 +3431,13 @@ public void TestNegPragmaWarningRestoreWithBadCode() ...@@ -3404,13 +3431,13 @@ public void TestNegPragmaWarningRestoreWithBadCode()
var text = @"#pragma warning restore CS1030"; var text = @"#pragma warning restore CS1030";
var node = Parse(text); var node = Parse(text);
TestRoundTripping(node, text, false); TestRoundTripping(node, text, false);
VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_InvalidNumber, Status = NodeStatus.IsWarning }); // CS1692 VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_StringOrNumericLiteralExpected, Status = NodeStatus.IsWarning }); // CS1072
VerifyDirectivePragma(node, new PragmaInfo VerifyDirectivePragma(node, new PragmaInfo
{ {
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia, PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword, WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.RestoreKeyword, DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
WarnginList = new int[] { -1 } // special case - no value WarningList = new int[] { -1 } // special case - no value
}); });
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册