Beispiel #1
0
        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());
        }