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);
        }
        private async Task SetSeverityHandlerAsync(ReportDiagnostic reportDiagnostic, DiagnosticData selectedDiagnostic, Project project)
        {
            try
            {
                using var token   = _listener.BeginAsyncOperation(nameof(SetSeverityHandlerAsync));
                using var context = _uiThreadOperationExecutor.BeginExecute(
                          title: ServicesVSResources.Updating_severity,
                          defaultDescription: ServicesVSResources.Updating_severity,
                          allowCancellation: true,
                          showProgress: true);

                var newSolution = await ConfigureSeverityAsync(context.UserCancellationToken).ConfigureAwait(false);

                var operations = ImmutableArray.Create <CodeActionOperation>(new ApplyChangesOperation(newSolution));
                using var scope = context.AddScope(allowCancellation: true, ServicesVSResources.Updating_severity);
                await _editHandlerService.ApplyAsync(
                    _workspace,
                    project.Solution,
                    fromDocument : null,
                    operations : operations,
                    title : ServicesVSResources.Updating_severity,
                    progressTracker : new UIThreadOperationContextProgressTracker(scope),
                    cancellationToken : context.UserCancellationToken).ConfigureAwait(false);

                if (selectedDiagnostic.DocumentId != null)
                {
                    // Kick off diagnostic re-analysis for affected document so that the configured diagnostic gets refreshed.
                    _ = Task.Run(() =>
                    {
                        _diagnosticService.Reanalyze(_workspace, documentIds: SpecializedCollections.SingletonEnumerable(selectedDiagnostic.DocumentId), highPriority: true);
                    });
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception ex) when(FatalError.ReportAndCatch(ex))
            {
            }

            return;

            // Local functions.
            async System.Threading.Tasks.Task <Solution> ConfigureSeverityAsync(CancellationToken cancellationToken)
            {
                var diagnostic = await selectedDiagnostic.ToDiagnosticAsync(project, cancellationToken).ConfigureAwait(false);

                return(await ConfigurationUpdater.ConfigureSeverityAsync(reportDiagnostic, diagnostic, project, cancellationToken).ConfigureAwait(false));
            }
        }
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);
        }
Example #4
0
        private async Task <bool> ContainsAnyFix(
            Document document, DiagnosticData diagnostic, CancellationToken cancellationToken)
        {
            var workspaceFixers    = ImmutableArray <CodeFixProvider> .Empty;
            var hasAnySharedFixer  = _workspaceFixersMap.TryGetValue(document.Project.Language, out var fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers);
            var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out var projectFixers);

            // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive
            if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive)
            {
                workspaceFixers   = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider);
                hasAnySharedFixer = workspaceFixers.Any();
            }

            Lazy <ISuppressionFixProvider> lazySuppressionProvider = null;
            var hasSuppressionFixer =
                _suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) &&
                lazySuppressionProvider.Value != null;

            if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasSuppressionFixer)
            {
                return(false);
            }

            var allFixers = ImmutableArray <CodeFixProvider> .Empty;

            if (hasAnySharedFixer)
            {
                allFixers = workspaceFixers;
            }

            if (hasAnyProjectFixer)
            {
                allFixers = allFixers.AddRange(projectFixers);
            }

            var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);

            if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressedOrUnsuppressed(dx))
            {
                return(true);
            }

            var fixes   = new List <CodeFix>();
            var context = new CodeFixContext(document, dx,

                                             // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs?
                                             (action, applicableDiagnostics) =>
            {
                // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from.
                lock (fixes)
                {
                    fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics));
                }
            },
                                             verifyArguments: false,
                                             cancellationToken: cancellationToken);

            var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>();

            // we do have fixer. now let's see whether it actually can fix it
            foreach (var fixer in allFixers)
            {
                await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false);

                foreach (var fix in fixes)
                {
                    if (!fix.Action.PerformFinalApplicabilityCheck)
                    {
                        return(true);
                    }

                    // Have to see if this fix is still applicable.  Jump to the foreground thread
                    // to make that check.
                    var applicable = await Task.Factory.StartNew(() =>
                    {
                        this.AssertIsForeground();
                        return(fix.Action.IsApplicable(document.Project.Solution.Workspace));
                    },
                                                                 cancellationToken, TaskCreationOptions.None, ForegroundTaskScheduler).ConfigureAwait(false);

                    this.AssertIsBackground();

                    if (applicable)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Example #5
0
        private async Task<bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, bool considerSuppressionFixes, CancellationToken cancellationToken)
        {
            ImmutableArray<CodeFixProvider> workspaceFixers = ImmutableArray<CodeFixProvider>.Empty;
            List<CodeFixProvider> projectFixers = null;

            Lazy<ImmutableDictionary<DiagnosticId, ImmutableArray<CodeFixProvider>>> fixerMap;
            bool hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers);
            var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out projectFixers);

            // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive
            if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive)
            {
                workspaceFixers = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider);
                hasAnySharedFixer = workspaceFixers.Any();
            }

            Lazy<ISuppressionFixProvider> lazySuppressionProvider = null;
            var hasSuppressionFixer =
                considerSuppressionFixes &&
                _suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) &&
                lazySuppressionProvider.Value != null;

            if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasSuppressionFixer)
            {
                return false;
            }

            var allFixers = ImmutableArray<CodeFixProvider>.Empty;
            if (hasAnySharedFixer)
            {
                allFixers = workspaceFixers;
            }

            if (hasAnyProjectFixer)
            {
                allFixers = allFixers.AddRange(projectFixers);
            }

            var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);

            if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressedOrUnsuppressed(dx))
            {
                return true;
            }

            var fixes = new List<CodeFix>();
            var context = new CodeFixContext(document, dx,

                // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs?
                (action, applicableDiagnostics) =>
                {
                    // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from.
                    lock (fixes)
                    {
                        fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics));
                    }
                },
                verifyArguments: false,
                cancellationToken: cancellationToken);

            var extensionManager = document.Project.Solution.Workspace.Services.GetService<IExtensionManager>();

            // we do have fixer. now let's see whether it actually can fix it
            foreach (var fixer in allFixers)
            {
                await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false);
                if (!fixes.Any())
                {
                    continue;
                }

                return true;
            }

            return false;
        }
Example #6
0
        private async Task<bool> ContainsAnyFixAsync(
            Document document, DiagnosticData diagnostic, CancellationToken cancellationToken)
        {
            var workspaceFixers = ImmutableArray<CodeFixProvider>.Empty;
            var hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out var fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers);
            var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out var projectFixers);

            // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive
            if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive)
            {
                workspaceFixers = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider);
                hasAnySharedFixer = workspaceFixers.Any();
            }

            var hasConfigurationFixer =
                _configurationProvidersMap.TryGetValue(document.Project.Language, out var lazyConfigurationProviders) &&
                !lazyConfigurationProviders.Value.IsDefaultOrEmpty;

            if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasConfigurationFixer)
            {
                return false;
            }

            var allFixers = ImmutableArray<CodeFixProvider>.Empty;
            if (hasAnySharedFixer)
            {
                allFixers = workspaceFixers;
            }

            if (hasAnyProjectFixer)
            {
                allFixers = allFixers.AddRange(projectFixers);
            }

            var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);

            if (hasConfigurationFixer)
            {
                foreach (var lazyConfigurationProvider in lazyConfigurationProviders.Value)
                {
                    if (lazyConfigurationProvider.IsFixableDiagnostic(dx))
                    {
                        return true;
                    }
                }
            }

            var fixes = new List<CodeFix>();
            var context = new CodeFixContext(document, dx,

                // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs?
                (action, applicableDiagnostics) =>
                {
                    // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from.
                    lock (fixes)
                    {
                        fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics));
                    }
                },
                verifyArguments: false,
                cancellationToken: cancellationToken);

            var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService<IExtensionManager>();

            // we do have fixer. now let's see whether it actually can fix it
            foreach (var fixer in allFixers)
            {
                await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? Task.CompletedTask).ConfigureAwait(false);
                foreach (var fix in fixes)
                {
                    if (!fix.Action.PerformFinalApplicabilityCheck)
                    {
                        return true;
                    }

                    // Have to see if this fix is still applicable.  Jump to the foreground thread
                    // to make that check.
                    await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken);
                    cancellationToken.ThrowIfCancellationRequested();

                    var applicable = fix.Action.IsApplicable(document.Project.Solution.Workspace);

                    await TaskScheduler.Default;

                    if (applicable)
                    {
                        return true;
                    }
                }
            }

            return false;
        }