提交 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 {
}
}
/// <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>
/// 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>
......
......@@ -3779,4 +3779,7 @@
<data name="OperationCausedStackOverflow" xml:space="preserve">
<value>Operation caused a stack overflow.</value>
</data>
<data name="WRN_StringOrNumericLiteralExpected" xml:space="preserve">
<value>String or numeric literal expected</value>
</data>
</root>
\ No newline at end of file
......@@ -644,6 +644,7 @@ internal enum ErrorCode
ERR_DottedTypeNameNotFoundInNSFwd = 1069,
ERR_SingleTypeNameNotFoundFwd = 1070,
//ERR_NoSuchMemberOnNoPIAType = 1071, //EE
WRN_StringOrNumericLiteralExpected = 1072,
// ERR_EOLExpected = 1099, // EE
// ERR_NotSupportedinEE = 1100, // EE
ERR_BadThisParam = 1100,
......
......@@ -276,6 +276,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_RefCultureMismatch:
case ErrorCode.WRN_ConflictingMachineAssembly:
case ErrorCode.WRN_FilterIsConstant:
case ErrorCode.WRN_StringOrNumericLiteralExpected:
return 1;
default:
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.Linq;
......@@ -374,32 +374,65 @@ private DirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, SyntaxToken
if (this.CurrentToken.Kind == SyntaxKind.DisableKeyword || this.CurrentToken.Kind == SyntaxKind.RestoreKeyword)
{
style = this.EatToken();
var codes = new SeparatedSyntaxListBuilder<ExpressionSyntax>(10);
var ids = new SeparatedSyntaxListBuilder<ExpressionSyntax>(10);
while (this.CurrentToken.Kind != SyntaxKind.EndOfDirectiveToken)
{
var code = this.EatToken(SyntaxKind.NumericLiteralToken, ErrorCode.WRN_InvalidNumber, reportError: isActive);
if (isActive && !code.IsMissing)
SyntaxToken id;
ExpressionSyntax idExpression;
if (this.CurrentToken.Kind == SyntaxKind.NumericLiteralToken || this.CurrentToken.Kind == SyntaxKind.StringLiteralToken)
{
int value = (int)code.Value;
if (ErrorFacts.GetSeverity((ErrorCode)value) != DiagnosticSeverity.Warning)
id = this.EatToken();
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;
codes.Add(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, code));
hasError = hasError || id.ContainsDiagnostics;
ids.Add(idExpression);
if (this.CurrentToken.Kind != SyntaxKind.CommaToken)
{
break;
}
codes.AddSeparator(this.EatToken());
ids.AddSeparator(this.EatToken());
}
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
{
......
......@@ -96,8 +96,10 @@ private static WarningStateMapEntry[] CreatePragmaWarningStateEntries(ImmutableA
if (currentDirective.ErrorCodes[x].IsMissing || currentDirective.ErrorCodes[x].ContainsDiagnostics)
continue;
int errorCode = (int)((LiteralExpressionSyntax)currentDirective.ErrorCodes[x]).Token.Value;
string errorId = MessageProvider.Instance.GetIdForErrorCode(errorCode);
var token = ((LiteralExpressionSyntax)currentDirective.ErrorCodes[x]).Token;
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
accumulatedSpecificWarningState = accumulatedSpecificWarningState.SetItem(errorId, directiveState);
......
......@@ -92,7 +92,7 @@ class C { }
ParserErrorMessageTests.ParseAndValidate(source,
Diagnostic(ErrorCode.WRN_IllegalPragma, ""),
Diagnostic(ErrorCode.WRN_IllegalPPWarning, ""),
Diagnostic(ErrorCode.WRN_InvalidNumber, "foo"),
Diagnostic(ErrorCode.WRN_StringOrNumericLiteralExpected, "foo"),
Diagnostic(ErrorCode.WRN_BadWarningNumber, "0").WithArguments("0"),
Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""),
Diagnostic(ErrorCode.WRN_IllegalPPChecksum, ""),
......
......@@ -45,7 +45,7 @@ internal struct PragmaInfo
public SyntaxKind PragmaKind;
public SyntaxKind WarningOrChecksumKind;
public SyntaxKind DisableOrRestoreKind;
public int[] WarnginList;
public int[] WarningList;
public string[] FileGuidByte;
}
......@@ -248,23 +248,34 @@ private void VerifyDirectivePragma(CSharpSyntaxNode node, PragmaInfo expected)
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);
}
else
{
Assert.Equal(expected.WarnginList.Length, pwd.ErrorCodes.Count);
Assert.Equal(expected.WarningList.Length, pwd.ErrorCodes.Count);
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 (w > 0)
if (warningNumber > 0)
{
Assert.Equal(w, wc.Value);
Assert.Equal(w, Int32.Parse(wc.Text));
var tokenKind = token.CSharpKind();
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()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 114 }
WarningList = new int[] { 114 }
});
}
......@@ -3307,7 +3318,7 @@ public void TestPragmaWarningDisableWithMultipleCodes()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 114, 162, 168 }
WarningList = new int[] { 114, 162, 168 }
});
}
......@@ -3335,7 +3346,7 @@ class A
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 440 }
WarningList = new int[] { 440 }
});
// verify that GetParseDiagnostics filters disabled warning
......@@ -3361,7 +3372,7 @@ public void TestRegressNegPragmaWarningDisableWithBadCode()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.DisableKeyword,
WarnginList = new int[] { 99999 }
WarningList = new int[] { 99999 }
});
}
......@@ -3377,7 +3388,7 @@ public void TestPragmaWarningRestore()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
WarnginList = new int[] { 114 }
WarningList = new int[] { 114 }
});
}
......@@ -3393,7 +3404,23 @@ public void TestPragmaWarningRestoreWithMultipleCodes()
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
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()
var text = @"#pragma warning restore CS1030";
var node = Parse(text);
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
{
PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
WarningOrChecksumKind = SyntaxKind.WarningKeyword,
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.
先完成此消息的编辑!
想要评论请 注册