提交 5cab7f2e 编写于 作者: T tmeschter

Extract diagnostic filtering logic out of the Compilations.

To allow filtering of diagnostics when you don't have a compilation, this change extracts the filtering logic into separate types. This makes it possible to, say, create a SyntaxTree and filter the resulting syntax diagnostics without needing a full compilation. (changeset 1256179)
上级 8dce02dc
......@@ -231,6 +231,7 @@
<Compile Include="Compilation\BuiltInOperators.cs" />
<Compile Include="Compilation\CSharpCompilation.cs" />
<Compile Include="Compilation\CSharpCompilationReference.cs" />
<Compile Include="Compilation\CSharpDiagnosticFilter.cs" />
<Compile Include="Compilation\CSharpSemanticModel.cs" />
<Compile Include="Compilation\ForEachStatementInfo.cs" />
<Compile Include="Compilation\InitializerSemanticModel.cs" />
......
......@@ -2027,10 +2027,6 @@ internal override bool FilterAndAppendAndFreeDiagnostics(DiagnosticBag accumulat
return result;
}
static ErrorCode[] AlinkWarnings = { ErrorCode.WRN_ConflictingMachineAssembly,
ErrorCode.WRN_RefCultureMismatch,
ErrorCode.WRN_InvalidVersionFormat };
internal override Diagnostic FilterDiagnostic(Diagnostic d)
{
return FilterDiagnostic(d, options);
......@@ -2038,44 +2034,7 @@ internal override Diagnostic FilterDiagnostic(Diagnostic d)
private static Diagnostic FilterDiagnostic(Diagnostic d, CSharpCompilationOptions options)
{
if (d == null) return d;
switch (d.Severity)
{
case DiagnosticSeverity.Error:
return d;
case InternalDiagnosticSeverity.Void:
return null;
default:
break;
}
//In the native compiler, all warnings originating from alink.dll were issued
//under the id WRN_ALinkWarn - 1607. If a customer used nowarn:1607 they would get
//none of those warnings. In Roslyn, we've given each of these warnings their
//own number, so that they may be configured independently. To preserve compatibility
//if a user has specifically configured 1607 and we are reporting one of the alink warnings, use
//the configuration specified for 1607. As implemented, this could result in customers
//specifying warnaserror:1607 and getting a message saying "warning as error CS8012..."
//We don't permit configuring 1607 and independently configuring the new warnings.
ReportDiagnostic reportAction;
if (AlinkWarnings.Contains((ErrorCode)d.Code) &&
options.SpecificDiagnosticOptions.Keys.Contains(CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_ALinkWarn)))
{
reportAction = GetDiagnosticReport(ErrorFacts.GetSeverity(ErrorCode.WRN_ALinkWarn),
d.IsEnabledByDefault,
CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_ALinkWarn),
ErrorFacts.GetWarningLevel(ErrorCode.WRN_ALinkWarn),
d.Location as Location,
options,
d.Category);
}
else
{
reportAction = GetDiagnosticReport(d.Severity, d.IsEnabledByDefault, d.Id, d.WarningLevel, d.Location as Location, options, d.Category);
}
return d.WithReportDiagnostic(reportAction);
return CSharpDiagnosticFilter.Filter(d, options.WarningLevel, options.GeneralDiagnosticOption, options.SpecificDiagnosticOptions);
}
/// <summary>
......@@ -2104,82 +2063,7 @@ private bool FilterAndAppendDiagnostics(DiagnosticBag accumulator, IEnumerable<D
return !hasErrorOrWarningAsError;
}
// Take a warning and return the final deposition of the given warning,
// based on both command line options and pragmas
internal static ReportDiagnostic GetDiagnosticReport(DiagnosticSeverity severity, bool isEnabledByDefault, string id, int warningLevel, Location location, CompilationOptions options, string category)
{
switch (severity)
{
case InternalDiagnosticSeverity.Void:
// If this is a deleted diagnostic, suppress it.
return ReportDiagnostic.Suppress;
case DiagnosticSeverity.Hidden:
// Compiler diagnostics cannot have severity Hidden, but user generated diagnostics can.
Debug.Assert(category != Diagnostic.CompilerDiagnosticCategory);
break;
case DiagnosticSeverity.Info:
if (category == Diagnostic.CompilerDiagnosticCategory)
{
// Don't modify compiler generated Info diagnostics.
return ReportDiagnostic.Default;
}
break;
case DiagnosticSeverity.Warning:
// Process warnings below.
break;
default:
throw ExceptionUtilities.UnexpectedValue(severity);
}
// Read options (e.g., /nowarn or /warnaserror)
ReportDiagnostic report = ReportDiagnostic.Default;
if (!options.SpecificDiagnosticOptions.TryGetValue(id, out report))
{
report = isEnabledByDefault ? ReportDiagnostic.Default : ReportDiagnostic.Suppress;
}
// Compute if the reporting should be suppressed.
if (warningLevel > options.WarningLevel // honor the warning level
|| report == ReportDiagnostic.Suppress) // check options (/nowarn)
{
return ReportDiagnostic.Suppress;
}
// If location is available, check out pragmas
if (location != null &&
location.SourceTree != null &&
((SyntaxTree)location.SourceTree).GetPragmaDirectiveWarningState(id, location.SourceSpan.Start) == ReportDiagnostic.Suppress)
{
return ReportDiagnostic.Suppress;
}
// Unless specific warning options are defined (/warnaserror[+|-]:<n> or /nowarn:<n>,
// follow the global option (/warnaserror[+|-] or /nowarn).
if (report == ReportDiagnostic.Default)
{
// If we've been asked to do warn-as-error then don't raise severity for anything below warning (info or hidden).
// When doing suppress-all-warnings, don't lower severity for anything other than warning and info
switch (options.GeneralDiagnosticOption)
{
case ReportDiagnostic.Error:
if (severity == DiagnosticSeverity.Warning)
{
return ReportDiagnostic.Error;
}
break;
case ReportDiagnostic.Suppress:
if (severity == DiagnosticSeverity.Warning || severity == DiagnosticSeverity.Info)
{
return ReportDiagnostic.Suppress;
}
break;
default:
break;
}
}
return report;
}
private ImmutableArray<Diagnostic> GetSourceDeclarationDiagnostics(SyntaxTree syntaxTree = null, TextSpan? filterSpanWithinTree = null, Func<IEnumerable<Diagnostic>, SyntaxTree, TextSpan?, IEnumerable<Diagnostic>> locationFilterOpt = null, CancellationToken cancellationToken = default(CancellationToken))
{
......
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
public static class CSharpDiagnosticFilter
{
private static readonly ErrorCode[] AlinkWarnings = { ErrorCode.WRN_ConflictingMachineAssembly,
ErrorCode.WRN_RefCultureMismatch,
ErrorCode.WRN_InvalidVersionFormat };
public static Diagnostic Filter(Diagnostic d, int warningLevelOption, ReportDiagnostic generalDiagnosticOption, IDictionary<string, ReportDiagnostic> specificDiagnosticOptions)
{
if (d == null) return d;
switch (d.Severity)
{
case DiagnosticSeverity.Error:
return d;
case InternalDiagnosticSeverity.Void:
return null;
default:
break;
}
//In the native compiler, all warnings originating from alink.dll were issued
//under the id WRN_ALinkWarn - 1607. If a customer used nowarn:1607 they would get
//none of those warnings. In Roslyn, we've given each of these warnings their
//own number, so that they may be configured independently. To preserve compatibility
//if a user has specifically configured 1607 and we are reporting one of the alink warnings, use
//the configuration specified for 1607. As implemented, this could result in customers
//specifying warnaserror:1607 and getting a message saying "warning as error CS8012..."
//We don't permit configuring 1607 and independently configuring the new warnings.
ReportDiagnostic reportAction;
if (AlinkWarnings.Contains((ErrorCode)d.Code) &&
specificDiagnosticOptions.Keys.Contains(CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_ALinkWarn)))
{
reportAction = GetDiagnosticReport(ErrorFacts.GetSeverity(ErrorCode.WRN_ALinkWarn),
d.IsEnabledByDefault,
CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_ALinkWarn),
ErrorFacts.GetWarningLevel(ErrorCode.WRN_ALinkWarn),
d.Location as Location,
d.Category,
warningLevelOption,
generalDiagnosticOption,
specificDiagnosticOptions);
}
else
{
reportAction = GetDiagnosticReport(d.Severity, d.IsEnabledByDefault, d.Id, d.WarningLevel, d.Location as Location, d.Category, warningLevelOption, generalDiagnosticOption, specificDiagnosticOptions);
}
return d.WithReportDiagnostic(reportAction);
}
// Take a warning and return the final deposition of the given warning,
// based on both command line options and pragmas
private static ReportDiagnostic GetDiagnosticReport(DiagnosticSeverity severity, bool isEnabledByDefault, string id, int diagnosticWarningLevel, Location location, string category, int warningLevelOption, ReportDiagnostic generalDiagnosticOption, IDictionary<string, ReportDiagnostic> specificDiagnosticOptions)
{
switch (severity)
{
case InternalDiagnosticSeverity.Void:
// If this is a deleted diagnostic, suppress it.
return ReportDiagnostic.Suppress;
case DiagnosticSeverity.Hidden:
// Compiler diagnostics cannot have severity Hidden, but user generated diagnostics can.
Debug.Assert(category != Diagnostic.CompilerDiagnosticCategory);
break;
case DiagnosticSeverity.Info:
if (category == Diagnostic.CompilerDiagnosticCategory)
{
// Don't modify compiler generated Info diagnostics.
return ReportDiagnostic.Default;
}
break;
case DiagnosticSeverity.Warning:
// Process warnings below.
break;
default:
throw ExceptionUtilities.UnexpectedValue(severity);
}
// Read options (e.g., /nowarn or /warnaserror)
ReportDiagnostic report = ReportDiagnostic.Default;
if (!specificDiagnosticOptions.TryGetValue(id, out report))
{
report = isEnabledByDefault ? ReportDiagnostic.Default : ReportDiagnostic.Suppress;
}
// Compute if the reporting should be suppressed.
if (diagnosticWarningLevel > warningLevelOption // honor the warning level
|| report == ReportDiagnostic.Suppress) // check options (/nowarn)
{
return ReportDiagnostic.Suppress;
}
// If location is available, check out pragmas
if (location != null &&
location.SourceTree != null &&
((SyntaxTree)location.SourceTree).GetPragmaDirectiveWarningState(id, location.SourceSpan.Start) == ReportDiagnostic.Suppress)
{
return ReportDiagnostic.Suppress;
}
// Unless specific warning options are defined (/warnaserror[+|-]:<n> or /nowarn:<n>,
// follow the global option (/warnaserror[+|-] or /nowarn).
if (report == ReportDiagnostic.Default)
{
// If we've been asked to do warn-as-error then don't raise severity for anything below warning (info or hidden).
// When doing suppress-all-warnings, don't lower severity for anything other than warning and info
switch (generalDiagnosticOption)
{
case ReportDiagnostic.Error:
if (severity == DiagnosticSeverity.Warning)
{
return ReportDiagnostic.Error;
}
break;
case ReportDiagnostic.Suppress:
if (severity == DiagnosticSeverity.Warning || severity == DiagnosticSeverity.Info)
{
return ReportDiagnostic.Suppress;
}
break;
default:
break;
}
}
return report;
}
}
}
......@@ -352,6 +352,7 @@
<Compile Include="Compilation\SynthesizedMetadataCompiler.vb" />
<Compile Include="Compilation\VisualBasicCompilation.vb" />
<Compile Include="Compilation\VisualBasicCompilationReference.vb" />
<Compile Include="Compilation\VisualBasicDiagnosticFilter.vb" />
<Compile Include="Declarations\Declaration.vb" />
<Compile Include="Declarations\DeclarationKind.vb" />
<Compile Include="Declarations\DeclarationModifiers.vb" />
......
......@@ -162,10 +162,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' </summary>
Private m_lazyEntryPoint As EntryPoint
Private Shared AlinkWarnings As ERRID() = {ERRID.WRN_ConflictingMachineAssembly,
ERRID.WRN_RefCultureMismatch,
ERRID.WRN_InvalidVersionFormat}
Public Overrides ReadOnly Property Language As String
Get
Return LanguageNames.VisualBasic
......@@ -1934,40 +1930,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function
Private Overloads Shared Function FilterDiagnostic(diagnostic As Diagnostic, options As CompilationOptions) As Diagnostic
' Filter void diagnostics so that our callers don't have to perform resolution
' (which might copy the list of diagnostics).
If (diagnostic.Severity = InternalDiagnosticSeverity.Void) Then
Return Nothing
End If
' If it is an error, keep it as it is.
If (diagnostic.Severity = DiagnosticSeverity.Error) Then
Return diagnostic
End If
'//In the native compiler, all warnings originating from alink.dll were issued
'//under the id WRN_ALinkWarn - 1607. If nowarn:1607 is used they would get
'//none of those warnings. In Roslyn, we've given each of these warnings their
'//own number, so that they may be configured independently. To preserve compatibility
'//if a user has specifically configured 1607 And we are reporting one of the alink warnings, use
'//the configuration specified for 1607. As implemented, this could result in
'//specifying warnaserror:1607 And getting a message saying "warning as error CS8012..."
'//We don't permit configuring 1607 and independently configuring the new warnings.
Dim report As ReportDiagnostic
If (AlinkWarnings.Contains(CType(diagnostic.Code, ERRID)) AndAlso
options.SpecificDiagnosticOptions.Keys.Contains(VisualBasic.MessageProvider.Instance.GetIdForErrorCode(ERRID.WRN_AssemblyGeneration1))) Then
report = GetDiagnosticReport(VisualBasic.MessageProvider.Instance.GetSeverity(ERRID.WRN_AssemblyGeneration1),
diagnostic.IsEnabledByDefault,
VisualBasic.MessageProvider.Instance.GetIdForErrorCode(ERRID.WRN_AssemblyGeneration1),
options,
diagnostic.Category)
Else
report = GetDiagnosticReport(diagnostic.Severity, diagnostic.IsEnabledByDefault, diagnostic.Id, options, diagnostic.Category)
End If
Return diagnostic.WithReportDiagnostic(report)
Return VisualBasicDiagnosticFilter.Filter(diagnostic, options.GeneralDiagnosticOption, options.SpecificDiagnosticOptions)
End Function
Friend Overrides Function FilterDiagnostic(diagnostic As Diagnostic) As Diagnostic
......@@ -1999,59 +1962,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return Not (hasError OrElse hasWarnAsError)
End Function
Private Shared Function GetDiagnosticReport(severity As DiagnosticSeverity, isEnabledByDefault As Boolean, id As String, options As CompilationOptions, category As String) As ReportDiagnostic
Select Case (severity)
Case InternalDiagnosticSeverity.Void
Return ReportDiagnostic.Suppress
Case DiagnosticSeverity.Hidden
' Compiler diagnostics cannot have severity Hidden, but user generated diagnostics can.
Debug.Assert(category <> Diagnostic.CompilerDiagnosticCategory)
' Leave Select
Case DiagnosticSeverity.Info
If category = Diagnostic.CompilerDiagnosticCategory Then
' Don't modify compiler generated Info diagnostics.
Return ReportDiagnostic.Default
End If
Case DiagnosticSeverity.Warning
' Leave Select
Case Else
Throw ExceptionUtilities.UnexpectedValue(severity)
End Select
' Read options (e.g., /nowarn or /warnaserror)
Dim report As ReportDiagnostic = ReportDiagnostic.Default
If Not options.SpecificDiagnosticOptions.TryGetValue(id, report) Then
report = If(isEnabledByDefault, ReportDiagnostic.Default, ReportDiagnostic.Suppress)
End If
' Compute if the reporting should be suppressed.
If report = ReportDiagnostic.Suppress Then
Return ReportDiagnostic.Suppress
End If
' check options (/nowarn)
' When doing suppress-all-warnings, don't lower severity for anything other than warning and info.
If options.GeneralDiagnosticOption = ReportDiagnostic.Suppress AndAlso
(severity = DiagnosticSeverity.Warning OrElse severity = DiagnosticSeverity.Info) Then
Return ReportDiagnostic.Suppress
End If
' check the AllWarningsAsErrors flag and the specific lists from /warnaserror[+|-] option.
' If we've been asked to do warn-as-error then don't raise severity for anything below warning (info or hidden).
If (options.GeneralDiagnosticOption = ReportDiagnostic.Error AndAlso severity = DiagnosticSeverity.Warning) Then
' In the case for both /warnaserror and /warnaserror-:<n> at the same time,
' do not report it as an error.
' If there has been no specific action for this warning, then turn it into an error.
If (report = ReportDiagnostic.Default) Then
Return ReportDiagnostic.Error
End If
End If
Return report
End Function
#End Region
#Region "Resources"
......
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
Public Class VisualBasicDiagnosticFilter
Private Shared ReadOnly AlinkWarnings As ERRID() = {ERRID.WRN_ConflictingMachineAssembly,
ERRID.WRN_RefCultureMismatch,
ERRID.WRN_InvalidVersionFormat}
Public Shared Function Filter(diagnostic As Diagnostic, generalDiagnosticOption As ReportDiagnostic, specificDiagnosticOptions As IDictionary(Of String, ReportDiagnostic)) As Diagnostic
' Filter void diagnostics so that our callers don't have to perform resolution
' (which might copy the list of diagnostics).
If (diagnostic.Severity = InternalDiagnosticSeverity.Void) Then
Return Nothing
End If
' If it is an error, keep it as it is.
If (diagnostic.Severity = DiagnosticSeverity.Error) Then
Return diagnostic
End If
' In the native compiler, all warnings originating from alink.dll were issued
' under the id WRN_ALinkWarn - 1607. If nowarn:1607 is used they would get
' none of those warnings. In Roslyn, we've given each of these warnings their
' own number, so that they may be configured independently. To preserve compatibility
' if a user has specifically configured 1607 And we are reporting one of the alink warnings, use
' the configuration specified for 1607. As implemented, this could result in
' specifying warnaserror:1607 And getting a message saying "warning as error CS8012..."
' We don't permit configuring 1607 and independently configuring the new warnings.
Dim report As ReportDiagnostic
If (AlinkWarnings.Contains(CType(diagnostic.Code, ERRID)) AndAlso
specificDiagnosticOptions.Keys.Contains(VisualBasic.MessageProvider.Instance.GetIdForErrorCode(ERRID.WRN_AssemblyGeneration1))) Then
report = GetDiagnosticReport(VisualBasic.MessageProvider.Instance.GetSeverity(ERRID.WRN_AssemblyGeneration1),
diagnostic.IsEnabledByDefault,
VisualBasic.MessageProvider.Instance.GetIdForErrorCode(ERRID.WRN_AssemblyGeneration1),
diagnostic.Category,
generalDiagnosticOption,
specificDiagnosticOptions)
Else
report = GetDiagnosticReport(diagnostic.Severity, diagnostic.IsEnabledByDefault, diagnostic.Id, diagnostic.Category, generalDiagnosticOption, specificDiagnosticOptions)
End If
Return diagnostic.WithReportDiagnostic(report)
End Function
Private Shared Function GetDiagnosticReport(severity As DiagnosticSeverity, isEnabledByDefault As Boolean, id As String, category As String, generalDiagnosticOption As ReportDiagnostic, specificDiagnosticOptions As IDictionary(Of String, ReportDiagnostic)) As ReportDiagnostic
Select Case (severity)
Case InternalDiagnosticSeverity.Void
Return ReportDiagnostic.Suppress
Case DiagnosticSeverity.Hidden
' Compiler diagnostics cannot have severity Hidden, but user generated diagnostics can.
Debug.Assert(category <> Diagnostic.CompilerDiagnosticCategory)
' Leave Select
Case DiagnosticSeverity.Info
If category = Diagnostic.CompilerDiagnosticCategory Then
' Don't modify compiler generated Info diagnostics.
Return ReportDiagnostic.Default
End If
Case DiagnosticSeverity.Warning
' Leave Select
Case Else
Throw ExceptionUtilities.UnexpectedValue(severity)
End Select
' Read options (e.g., /nowarn or /warnaserror)
Dim report As ReportDiagnostic = ReportDiagnostic.Default
If Not specificDiagnosticOptions.TryGetValue(id, report) Then
report = If(isEnabledByDefault, ReportDiagnostic.Default, ReportDiagnostic.Suppress)
End If
' Compute if the reporting should be suppressed.
If report = ReportDiagnostic.Suppress Then
Return ReportDiagnostic.Suppress
End If
' check options (/nowarn)
' When doing suppress-all-warnings, don't lower severity for anything other than warning and info.
If generalDiagnosticOption = ReportDiagnostic.Suppress AndAlso
(severity = DiagnosticSeverity.Warning OrElse severity = DiagnosticSeverity.Info) Then
Return ReportDiagnostic.Suppress
End If
' check the AllWarningsAsErrors flag and the specific lists from /warnaserror[+|-] option.
' If we've been asked to do warn-as-error then don't raise severity for anything below warning (info or hidden).
If (generalDiagnosticOption = ReportDiagnostic.Error AndAlso severity = DiagnosticSeverity.Warning) Then
' In the case for both /warnaserror and /warnaserror-:<n> at the same time,
' do not report it as an error.
' If there has been no specific action for this warning, then turn it into an error.
If (report = ReportDiagnostic.Default) Then
Return ReportDiagnostic.Error
End If
End If
Return report
End Function
End Class
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册