Example #1
0
        private static void WriteTo(ObjectWriter writer, DiagnosticDataLocation item, CancellationToken cancellationToken)
        {
            if (item == null)
            {
                writer.WriteBoolean(false);
                return;
            }
            else
            {
                writer.WriteBoolean(true);
            }

            if (item.SourceSpan.HasValue)
            {
                writer.WriteBoolean(true);
                writer.WriteInt32(item.SourceSpan.Value.Start);
                writer.WriteInt32(item.SourceSpan.Value.Length);
            }
            else
            {
                writer.WriteBoolean(false);
            }

            writer.WriteString(item.OriginalFilePath);
            writer.WriteInt32(item.OriginalStartLine);
            writer.WriteInt32(item.OriginalStartColumn);
            writer.WriteInt32(item.OriginalEndLine);
            writer.WriteInt32(item.OriginalEndColumn);

            writer.WriteString(item.MappedFilePath);
            writer.WriteInt32(item.MappedStartLine);
            writer.WriteInt32(item.MappedStartColumn);
            writer.WriteInt32(item.MappedEndLine);
            writer.WriteInt32(item.MappedEndColumn);
        }
        public async Task DiagnosticData_SourceGeneratedDocumentLocationIsPreserved()
        {
            var content = @"
namespace B
{
    class A
    {
    }
}
";

            using var workspace = TestWorkspace.CreateCSharp(files: Array.Empty <string>(), sourceGeneratedFiles: new[] { content }, composition: EditorTestCompositions.EditorFeatures);
            var hostDocument = workspace.Documents.Single();

            Assert.True(hostDocument.IsSourceGenerated);

            var documentId = hostDocument.Id;
            var project    = workspace.CurrentSolution.GetRequiredProject(documentId.ProjectId);
            var document   = await project.GetSourceGeneratedDocumentAsync(documentId, CancellationToken.None);

            await VerifyTextSpanAsync(content, 3, 10, 3, 11, new TextSpan(28, 1));

            var location = new DiagnosticDataLocation(
                documentId, sourceSpan: new TextSpan(28, 1), originalFilePath: document.FilePath,
                originalStartLine: 3, originalStartColumn: 10, originalEndLine: 3, originalEndColumn: 11);

            var diagnosticData = new DiagnosticData(
                id: "test1",
                category: "Test",
                message: "test1 message",
                severity: DiagnosticSeverity.Info,
                defaultSeverity: DiagnosticSeverity.Info,
                isEnabledByDefault: true,
                warningLevel: 1,
                projectId: documentId.ProjectId,
                customTags: ImmutableArray <string> .Empty,
                properties: ImmutableDictionary <string, string> .Empty,
                location: location,
                additionalLocations: ImmutableArray <DiagnosticDataLocation> .Empty,
                language: project.Language);

            var diagnostic = await diagnosticData.ToDiagnosticAsync(project, CancellationToken.None);

            var roundTripDiagnosticData = DiagnosticData.Create(diagnostic, document);

            var roundTripLocation = roundTripDiagnosticData.DataLocation;

            Assert.NotNull(roundTripDiagnosticData.DataLocation);
            Assert.Equal(location.DocumentId, roundTripLocation.DocumentId);
            Assert.Equal(location.SourceSpan, roundTripLocation.SourceSpan);
            Assert.Equal(location.OriginalFilePath, roundTripLocation.OriginalFilePath);
            Assert.Equal(location.OriginalStartLine, roundTripLocation.OriginalStartLine);
            Assert.Equal(location.OriginalStartColumn, roundTripLocation.OriginalStartColumn);
            Assert.Equal(location.OriginalEndLine, roundTripLocation.OriginalEndLine);
            Assert.Equal(location.OriginalEndLine, roundTripLocation.OriginalEndLine);
        }
Example #3
0
        public async Task DiagnosticData_ExternalAdditionalLocationIsPreserved()
        {
            using var workspace = new TestWorkspace(composition: EditorTestCompositions.EditorFeatures);

            var additionalDocument = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp)
                                     .AddDocument("test.cs", "")
                                     .Project.AddAdditionalDocument("AdditionalDocument.txt", "First line in file", filePath: "AdditionalDocument.txt");
            var document = additionalDocument.Project.Documents.Single();

            var externalAdditionalLocation = new DiagnosticDataLocation(
                additionalDocument.Id, sourceSpan: new TextSpan(0, 1), originalFilePath: additionalDocument.Name,
                originalStartLine: 0, originalStartColumn: 0, originalEndLine: 0, originalEndColumn: 1);

            var diagnosticData = new DiagnosticData(
                id: "test1",
                category: "Test",
                message: "test1 message",
                enuMessageForBingSearch: "test1 message format",
                severity: DiagnosticSeverity.Info,
                defaultSeverity: DiagnosticSeverity.Info,
                isEnabledByDefault: true,
                warningLevel: 1,
                projectId: document.Project.Id,
                customTags: ImmutableArray <string> .Empty,
                properties: ImmutableDictionary <string, string> .Empty,
                location: new DiagnosticDataLocation(document.Id),
                additionalLocations: new[] { externalAdditionalLocation },
                language: document.Project.Language);

            var diagnostic = await diagnosticData.ToDiagnosticAsync(document.Project, CancellationToken.None);

            var roundTripDiagnosticData = DiagnosticData.Create(diagnostic, document);

            var roundTripAdditionalLocation = Assert.Single(roundTripDiagnosticData.AdditionalLocations);

            Assert.Equal(externalAdditionalLocation.DocumentId, roundTripAdditionalLocation.DocumentId);
            Assert.Equal(externalAdditionalLocation.SourceSpan, roundTripAdditionalLocation.SourceSpan);
            Assert.Equal(externalAdditionalLocation.OriginalFilePath, roundTripAdditionalLocation.OriginalFilePath);
            Assert.Equal(externalAdditionalLocation.OriginalStartLine, roundTripAdditionalLocation.OriginalStartLine);
            Assert.Equal(externalAdditionalLocation.OriginalStartColumn, roundTripAdditionalLocation.OriginalStartColumn);
            Assert.Equal(externalAdditionalLocation.OriginalEndLine, roundTripAdditionalLocation.OriginalEndLine);
            Assert.Equal(externalAdditionalLocation.OriginalEndLine, roundTripAdditionalLocation.OriginalEndLine);
        }
        /// <summary>
        /// Gets <see cref="DiagnosticData"/> objects for selected error list entries.
        /// For remove suppression, the method also returns selected external source diagnostics.
        /// </summary>
        public async Task <ImmutableArray <DiagnosticData> > GetSelectedItemsAsync(bool isAddSuppression, CancellationToken cancellationToken)
        {
            var builder = ImmutableArray.CreateBuilder <DiagnosticData>();
            Dictionary <string, Project> projectNameToProjectMapOpt = null;
            Dictionary <Project, ImmutableDictionary <string, Document> > filePathToDocumentMapOpt = null;

            foreach (var entryHandle in _tableControl.SelectedEntries)
            {
                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.
                    DiagnosticDataLocation location = null;

                    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 = new DiagnosticDataLocation(document.Id, textSpan, filePath,
                                                                  originalStartLine: linePosition.Line, originalStartColumn: linePosition.Character,
                                                                  originalEndLine: linePosition.Line, originalEndColumn: linePosition.Character);
                        }

                        Contract.ThrowIfNull(project);
                        Contract.ThrowIfFalse((document != null) == (location != null));

                        // 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).
                        diagnosticData = new DiagnosticData(
                            id: errorCode,
                            category: category,
                            message: message,
                            enuMessageForBingSearch: message,
                            severity: DiagnosticSeverity.Warning,
                            defaultSeverity: DiagnosticSeverity.Warning,
                            isEnabledByDefault: true,
                            warningLevel: 1,
                            isSuppressed: isSuppressedEntry,
                            title: message,
                            location: location,
                            customTags: SuppressionHelpers.SynthesizedExternalSourceDiagnosticCustomTags,
                            properties: ImmutableDictionary <string, string> .Empty,
                            workspace: _workspace,
                            projectId: project.Id);
                    }
                }

                if (IsEntryWithConfigurableSuppressionState(diagnosticData))
                {
                    builder.Add(diagnosticData);
                }
            }

            return(builder.ToImmutable());
        }
        private static void WriteTo(ObjectWriter writer, DiagnosticDataLocation item, CancellationToken cancellationToken)
        {
            if (item == null)
            {
                writer.WriteBoolean(false);
                return;
            }
            else
            {
                writer.WriteBoolean(true);
            }

            if (item.SourceSpan.HasValue)
            {
                writer.WriteBoolean(true);
                writer.WriteInt32(item.SourceSpan.Value.Start);
                writer.WriteInt32(item.SourceSpan.Value.Length);
            }
            else
            {
                writer.WriteBoolean(false);
            }

            writer.WriteString(item.OriginalFilePath);
            writer.WriteInt32(item.OriginalStartLine);
            writer.WriteInt32(item.OriginalStartColumn);
            writer.WriteInt32(item.OriginalEndLine);
            writer.WriteInt32(item.OriginalEndColumn);

            writer.WriteString(item.MappedFilePath);
            writer.WriteInt32(item.MappedStartLine);
            writer.WriteInt32(item.MappedStartColumn);
            writer.WriteInt32(item.MappedEndLine);
            writer.WriteInt32(item.MappedEndColumn);
        }
        private DiagnosticDataLocation UpdateDiagnosticLocation(
            DiagnosticDataLocation dataLocation, SyntaxTree tree, int delta)
        {
            var span = dataLocation.SourceSpan.Value;
            var start = Math.Min(Math.Max(span.Start + delta, 0), tree.Length);
            var newSpan = new TextSpan(start, start >= tree.Length ? 0 : span.Length);

            var mappedLineInfo = tree.GetMappedLineSpan(newSpan);
            var originalLineInfo = tree.GetLineSpan(newSpan);

            return new DiagnosticDataLocation(dataLocation.DocumentId, newSpan,
                originalFilePath: originalLineInfo.Path,
                originalStartLine: originalLineInfo.StartLinePosition.Line,
                originalStartColumn: originalLineInfo.StartLinePosition.Character,
                originalEndLine: originalLineInfo.EndLinePosition.Line,
                originalEndColumn: originalLineInfo.EndLinePosition.Character,
                mappedFilePath: mappedLineInfo.GetMappedFilePathIfExist(),
                mappedStartLine: mappedLineInfo.StartLinePosition.Line,
                mappedStartColumn: mappedLineInfo.StartLinePosition.Character,
                mappedEndLine: mappedLineInfo.EndLinePosition.Line,
                mappedEndColumn: mappedLineInfo.EndLinePosition.Character);
        }
Example #7
0
                public override bool TryGetValue(int index, string columnName, out object content)
                {
                    // REVIEW: this method is too-chatty to make async, but otherwise, how one can implement it async?
                    //         also, what is cancellation mechanism?
                    var item = GetItem(index);

                    var data = item?.Data;

                    if (data == null)
                    {
                        content = null;
                        return(false);
                    }

                    switch (columnName)
                    {
                    case StandardTableKeyNames.Priority:
                        content = ValueTypeCache.GetOrCreate((VSTASKPRIORITY)data.Value.Priority);
                        return(content != null);

                    case StandardTableKeyNames.Text:
                        content = data.Value.Message;
                        return(content != null);

                    case StandardTableKeyNames.DocumentName:
                        content = DiagnosticDataLocation.GetFilePath(data.Value.OriginalFilePath, data.Value.MappedFilePath);
                        return(content != null);

                    case StandardTableKeyNames.Line:
                        content = GetLineColumn(item).Line;
                        return(true);

                    case StandardTableKeyNames.Column:
                        content = GetLineColumn(item).Character;
                        return(true);

                    case StandardTableKeyNames.TaskCategory:
                        content = ValueTypeCache.GetOrCreate(VSTASKCATEGORY.CAT_COMMENTS);
                        return(content != null);

                    case StandardTableKeyNames.ProjectName:
                        content = item.ProjectName;
                        return(content != null);

                    case ProjectNames:
                        var names = item.ProjectNames;
                        content = names;
                        return(names.Length > 0);

                    case StandardTableKeyNames.ProjectGuid:
                        content = ValueTypeCache.GetOrCreate(item.ProjectGuid);
                        return((Guid)content != Guid.Empty);

                    case ProjectGuids:
                        var guids = item.ProjectGuids;
                        content = guids;
                        return(guids.Length > 0);

                    default:
                        content = null;
                        return(false);
                    }
                }