private static IEnumerable <DiagnosticData> FilterDiagnostics(IEnumerable <DiagnosticData> diagnostics, bool isAddSuppression, bool isSuppressionInSource, bool onlyCompilerDiagnostics) { foreach (var diagnostic in diagnostics) { var isCompilerDiagnostic = SuppressionHelpers.IsCompilerDiagnostic(diagnostic); if (onlyCompilerDiagnostics && !isCompilerDiagnostic) { continue; } if (isAddSuppression) { // Compiler diagnostics can only be suppressed in source. if (!diagnostic.IsSuppressed && (isSuppressionInSource || !isCompilerDiagnostic)) { yield return(diagnostic); } } else if (diagnostic.IsSuppressed) { yield return(diagnostic); } } }
private static bool EntrySupportsSuppressionState(ITableEntryHandle entryHandle, out bool isRoslynEntry, out bool isSuppressedEntry, out bool isCompilerDiagnosticEntry, out bool isNoLocationDiagnosticEntry) { string filePath; isNoLocationDiagnosticEntry = !entryHandle.TryGetValue(StandardTableColumnDefinitions.DocumentName, out filePath) || string.IsNullOrEmpty(filePath); int index; var roslynSnapshot = GetEntriesSnapshot(entryHandle, out index); if (roslynSnapshot == null) { isRoslynEntry = false; isCompilerDiagnosticEntry = false; return(IsNonRoslynEntrySupportingSuppressionState(entryHandle, out isSuppressedEntry)); } var diagnosticData = roslynSnapshot?.GetItem(index)?.Primary; if (!IsEntryWithConfigurableSuppressionState(diagnosticData)) { isRoslynEntry = false; isSuppressedEntry = false; isCompilerDiagnosticEntry = false; return(false); } isRoslynEntry = true; isSuppressedEntry = diagnosticData.IsSuppressed; isCompilerDiagnosticEntry = SuppressionHelpers.IsCompilerDiagnostic(diagnosticData); return(true); }
/// <summary> /// Gets <see cref="DiagnosticData"/> objects for error list entries, filtered based on the given parameters. /// </summary> public async Task <ImmutableArray <DiagnosticData> > GetItemsAsync(bool selectedEntriesOnly, bool isAddSuppression, bool isSuppressionInSource, bool onlyCompilerDiagnostics, CancellationToken cancellationToken) { var builder = ImmutableArray.CreateBuilder <DiagnosticData>(); Dictionary <string, Project> projectNameToProjectMapOpt = null; Dictionary <Project, ImmutableDictionary <string, Document> > filePathToDocumentMapOpt = null; var entries = selectedEntriesOnly ? _tableControl.SelectedEntries : _tableControl.Entries; foreach (var entryHandle in entries) { cancellationToken.ThrowIfCancellationRequested(); DiagnosticData diagnosticData = null; int index; var roslynSnapshot = GetEntriesSnapshot(entryHandle, out index); if (roslynSnapshot != null) { diagnosticData = roslynSnapshot.GetItem(index)?.Primary; } else if (!isAddSuppression) { // For suppression removal, we also need to handle FxCop entries. bool isSuppressedEntry; if (!IsNonRoslynEntrySupportingSuppressionState(entryHandle, out isSuppressedEntry) || !isSuppressedEntry) { continue; } string errorCode = null, category = null, message = null, filePath = null, projectName = null; int line = -1; // FxCop only supports line, not column. var location = Location.None; if (entryHandle.TryGetValue(StandardTableColumnDefinitions.ErrorCode, out errorCode) && !string.IsNullOrEmpty(errorCode) && entryHandle.TryGetValue(StandardTableColumnDefinitions.ErrorCategory, out category) && !string.IsNullOrEmpty(category) && entryHandle.TryGetValue(StandardTableColumnDefinitions.Text, out message) && !string.IsNullOrEmpty(message) && entryHandle.TryGetValue(StandardTableColumnDefinitions.ProjectName, out projectName) && !string.IsNullOrEmpty(projectName)) { if (projectNameToProjectMapOpt == null) { projectNameToProjectMapOpt = new Dictionary <string, Project>(); foreach (var p in _workspace.CurrentSolution.Projects) { projectNameToProjectMapOpt[p.Name] = p; } } cancellationToken.ThrowIfCancellationRequested(); Project project; if (!projectNameToProjectMapOpt.TryGetValue(projectName, out project)) { // bail out continue; } Document document = null; var hasLocation = (entryHandle.TryGetValue(StandardTableColumnDefinitions.DocumentName, out filePath) && !string.IsNullOrEmpty(filePath)) && (entryHandle.TryGetValue(StandardTableColumnDefinitions.Line, out line) && line >= 0); if (hasLocation) { if (string.IsNullOrEmpty(filePath) || line < 0) { // bail out continue; } ImmutableDictionary <string, Document> filePathMap; filePathToDocumentMapOpt = filePathToDocumentMapOpt ?? new Dictionary <Project, ImmutableDictionary <string, Document> >(); if (!filePathToDocumentMapOpt.TryGetValue(project, out filePathMap)) { filePathMap = await GetFilePathToDocumentMapAsync(project, cancellationToken).ConfigureAwait(false); filePathToDocumentMapOpt[project] = filePathMap; } if (!filePathMap.TryGetValue(filePath, out document)) { // bail out continue; } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var linePosition = new LinePosition(line, 0); var linePositionSpan = new LinePositionSpan(start: linePosition, end: linePosition); var textSpan = (await tree.GetTextAsync(cancellationToken).ConfigureAwait(false)).Lines.GetTextSpan(linePositionSpan); location = tree.GetLocation(textSpan); } Contract.ThrowIfNull(project); Contract.ThrowIfFalse((document != null) == location.IsInSource); // Create a diagnostic with correct values for fields we care about: id, category, message, isSuppressed, location // and default values for the rest of the fields (not used by suppression fixer). var diagnostic = Diagnostic.Create( id: errorCode, category: category, message: message, severity: DiagnosticSeverity.Warning, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, warningLevel: 1, isSuppressed: isSuppressedEntry, title: message, location: location, customTags: SuppressionHelpers.SynthesizedExternalSourceDiagnosticCustomTags); diagnosticData = document != null? DiagnosticData.Create(document, diagnostic) : DiagnosticData.Create(project, diagnostic); } } if (IsEntryWithConfigurableSuppressionState(diagnosticData)) { var isCompilerDiagnostic = SuppressionHelpers.IsCompilerDiagnostic(diagnosticData); if (onlyCompilerDiagnostics && !isCompilerDiagnostic) { continue; } if (isAddSuppression) { // Compiler diagnostics can only be suppressed in source. if (!diagnosticData.IsSuppressed && (isSuppressionInSource || !isCompilerDiagnostic)) { builder.Add(diagnosticData); } } else if (diagnosticData.IsSuppressed) { builder.Add(diagnosticData); } } } return(builder.ToImmutable()); }