From 66a725d4caa6187a0a8bf1c8dcc767857a92e911 Mon Sep 17 00:00:00 2001 From: filipw Date: Wed, 18 Nov 2020 13:28:49 +0100 Subject: [PATCH 1/8] added logging of the editorconfig files attached to the project --- src/OmniSharp.MSBuild/ProjectManager.cs | 1 + src/OmniSharp.Roslyn/OmniSharpWorkspace.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index 011adda8af..aa33f12e17 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -546,6 +546,7 @@ private void UpdateAnalyzerConfigFiles(Project project, IList analyzerCo { if (File.Exists(file)) { + _logger.LogDebug($".editorconfig file for project {project.Name}: {file}"); _workspace.AddAnalyzerConfigDocument(project.Id, file); } } diff --git a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs index e178359fc7..bbf6ae4064 100644 --- a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs +++ b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs @@ -149,6 +149,7 @@ public DocumentId TryAddMiscellaneousDocument(string filePath, TextLoader loader var newAnalyzerConfigFiles = EditorConfigFinder .GetEditorConfigPaths(filePath) .Except(analyzerConfigFiles); + foreach (var analyzerConfigFile in newAnalyzerConfigFiles) { AddAnalyzerConfigDocument(projectInfo.Id, analyzerConfigFile); From 0c67da303404f578c2edd5a207aa437019fc2681 Mon Sep 17 00:00:00 2001 From: filipw Date: Wed, 18 Nov 2020 13:31:54 +0100 Subject: [PATCH 2/8] more logging on unhappy paths --- src/OmniSharp.MSBuild/ProjectManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index aa33f12e17..56c05a1d82 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -533,6 +533,7 @@ private void UpdateAnalyzerConfigFiles(Project project, IList analyzerCo { if (!_workspace.EditorConfigEnabled) { + _logger.LogDebug($".editorconfig files were configured by the project {project.Name} but will not be respected because the feature is switched off in OmniSharp. Enable .editorconfig support in OmniSharp to take advantage of them."); return; } @@ -549,6 +550,10 @@ private void UpdateAnalyzerConfigFiles(Project project, IList analyzerCo _logger.LogDebug($".editorconfig file for project {project.Name}: {file}"); _workspace.AddAnalyzerConfigDocument(project.Id, file); } + else + { + _logger.LogDebug($".editorconfig file for project {project.Name}: {file} was expected but not found on disk."); + } } } From 5fdad6308bd604e8ce4b0a39b44123a2df4926cf Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 16:46:46 +0100 Subject: [PATCH 3/8] fixed disappearing editorconfig state --- .../ProjectFile/ProjectFileInfoExtensions.cs | 10 +++++++--- src/OmniSharp.MSBuild/ProjectManager.cs | 20 +++++++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs index b75c1ec1cb..6117779989 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs @@ -15,10 +15,14 @@ internal static class ProjectFileInfoExtensions public static CSharpCompilationOptions CreateCompilationOptions(this ProjectFileInfo projectFileInfo) { var compilationOptions = new CSharpCompilationOptions(projectFileInfo.OutputKind); + return projectFileInfo.CreateCompilationOptions(compilationOptions); + } - compilationOptions = compilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) - .WithSpecificDiagnosticOptions(projectFileInfo.GetDiagnosticOptions()) - .WithOverflowChecks(projectFileInfo.CheckForOverflowUnderflow); + public static CSharpCompilationOptions CreateCompilationOptions(this ProjectFileInfo projectFileInfo, CSharpCompilationOptions existingCompilationOptions) + { + var compilationOptions = existingCompilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) + .WithSpecificDiagnosticOptions(projectFileInfo.GetDiagnosticOptions()) + .WithOverflowChecks(projectFileInfo.CheckForOverflowUnderflow); if (projectFileInfo.AllowUnsafeCode) { diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index 56c05a1d82..fc5ebd970a 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -465,15 +465,31 @@ private void UpdateProject(string projectFilePath) UpdateSourceFiles(project, projectFileInfo.SourceFiles); UpdateParseOptions(project, projectFileInfo.LanguageVersion, projectFileInfo.PreprocessorSymbolNames, !string.IsNullOrWhiteSpace(projectFileInfo.DocumentationFile)); UpdateProjectReferences(project, projectFileInfo.ProjectReferences); + UpdateAnalyzerConfigFiles(project, projectFileInfo.AnalyzerConfigFiles); UpdateReferences(project, projectFileInfo.ProjectReferences, projectFileInfo.References); UpdateAnalyzerReferences(project, projectFileInfo); UpdateAdditionalFiles(project, projectFileInfo.AdditionalFiles); - UpdateAnalyzerConfigFiles(project, projectFileInfo.AnalyzerConfigFiles); UpdateProjectProperties(project, projectFileInfo); _workspace.AddDocumentInclusionRuleForProject(project.Id, (path) => projectFileInfo.IsFileIncluded(path)); _workspace.TryPromoteMiscellaneousDocumentsToProject(project); - _workspace.UpdateCompilationOptionsForProject(project.Id, projectFileInfo.CreateCompilationOptions()); + + UpdateCompilationOptions(project, projectFileInfo); + } + + private void UpdateCompilationOptions(Project project, ProjectFileInfo projectFileInfo) + { + // if project already has compilation options, then we shall use that to compute new compilation options based on the project file + // and then only set those if it's really necessary + if (project.CompilationOptions != null && project.CompilationOptions is CSharpCompilationOptions existingCompilationOptions) + { + var newCompilationOptions = projectFileInfo.CreateCompilationOptions(existingCompilationOptions); + if (newCompilationOptions != existingCompilationOptions) + { + _workspace.UpdateCompilationOptionsForProject(project.Id, existingCompilationOptions); + _logger.LogDebug("Updated project compilation options on project {project.Id}."); + } + } } private void UpdateAnalyzerReferences(Project project, ProjectFileInfo projectFileInfo) From 97fa691f880738f4d51aa084f9db0865d5556b66 Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 16:47:10 +0100 Subject: [PATCH 4/8] trigger re-analysis when editorconfig document is re-added --- .../Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs index 8b35a3c36c..a6d0933a15 100644 --- a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs +++ b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs @@ -176,6 +176,9 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs changeEv case WorkspaceChangeKind.ProjectAdded: case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: + // at the moment we remove and re-add analyzer documents when project update is requested + // therefore it is enough to just listen to "AnalyzerConfigDocumentAdded" event to trigger re-analysis + case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: _logger.LogDebug($"Project {changeEvent.ProjectId} updated, reanalyzing its diagnostics."); var projectDocumentIds = _workspace.CurrentSolution.GetProject(changeEvent.ProjectId).Documents.Select(x => x.Id).ToImmutableArray(); QueueForAnalysis(projectDocumentIds, AnalyzerWorkType.Background); From ee0d28e211790249b8523be01f0f5e2aa82f8945 Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 17:02:31 +0100 Subject: [PATCH 5/8] fixed compilation options --- .../ProjectFile/ProjectFileInfoExtensions.cs | 10 ++++------ src/OmniSharp.MSBuild/ProjectManager.cs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs index 6117779989..81ae4df6a0 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs @@ -24,15 +24,13 @@ public static CSharpCompilationOptions CreateCompilationOptions(this ProjectFile .WithSpecificDiagnosticOptions(projectFileInfo.GetDiagnosticOptions()) .WithOverflowChecks(projectFileInfo.CheckForOverflowUnderflow); - if (projectFileInfo.AllowUnsafeCode) + if (projectFileInfo.AllowUnsafeCode != compilationOptions.AllowUnsafe) { - compilationOptions = compilationOptions.WithAllowUnsafe(true); + compilationOptions = compilationOptions.WithAllowUnsafe(projectFileInfo.AllowUnsafeCode); } - if (projectFileInfo.TreatWarningsAsErrors) - { - compilationOptions = compilationOptions.WithGeneralDiagnosticOption(ReportDiagnostic.Error); - } + compilationOptions = projectFileInfo.TreatWarningsAsErrors ? + compilationOptions.WithGeneralDiagnosticOption(ReportDiagnostic.Error) : compilationOptions.WithGeneralDiagnosticOption(ReportDiagnostic.Default); if (projectFileInfo.NullableContextOptions != compilationOptions.NullableContextOptions) { diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index fc5ebd970a..5ddbfeb407 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -486,7 +486,7 @@ private void UpdateCompilationOptions(Project project, ProjectFileInfo projectFi var newCompilationOptions = projectFileInfo.CreateCompilationOptions(existingCompilationOptions); if (newCompilationOptions != existingCompilationOptions) { - _workspace.UpdateCompilationOptionsForProject(project.Id, existingCompilationOptions); + _workspace.UpdateCompilationOptionsForProject(project.Id, newCompilationOptions); _logger.LogDebug("Updated project compilation options on project {project.Id}."); } } From 9d69446e8c2aa36f7e687c10a0e8dd30cd37768a Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 20:35:07 +0100 Subject: [PATCH 6/8] handle individual editorconfig updates --- src/OmniSharp.MSBuild/ProjectManager.cs | 69 ++++++++++++++----- .../CSharpDiagnosticWorkerWithAnalyzers.cs | 10 +-- src/OmniSharp.Roslyn/OmniSharpWorkspace.cs | 6 ++ 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index 5ddbfeb407..44a051465b 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -37,12 +37,14 @@ private class ProjectToUpdate public ProjectIdInfo ProjectIdInfo; public string FilePath { get; } public bool AllowAutoRestore { get; set; } + public string ChangeTriggerPath { get; } public ProjectLoadedEventArgs LoadedEventArgs { get; set; } - public ProjectToUpdate(string filePath, bool allowAutoRestore, ProjectIdInfo projectIdInfo) + public ProjectToUpdate(string filePath, bool allowAutoRestore, ProjectIdInfo projectIdInfo, string changeTriggerPath) { ProjectIdInfo = projectIdInfo ?? throw new ArgumentNullException(nameof(projectIdInfo)); FilePath = filePath ?? throw new ArgumentNullException(nameof(filePath)); + ChangeTriggerPath = changeTriggerPath; AllowAutoRestore = allowAutoRestore; } } @@ -158,10 +160,10 @@ protected override void DisposeCore(bool disposing) public IEnumerable GetAllProjects() => _projectFiles.GetItems(); public bool TryGetProject(string projectFilePath, out ProjectFileInfo projectFileInfo) => _projectFiles.TryGetValue(projectFilePath, out projectFileInfo); - public void QueueProjectUpdate(string projectFilePath, bool allowAutoRestore, ProjectIdInfo projectId) + public void QueueProjectUpdate(string projectFilePath, bool allowAutoRestore, ProjectIdInfo projectId, string changeTriggerFilePath = null) { _logger.LogInformation($"Queue project update for '{projectFilePath}'"); - _queue.Post(new ProjectToUpdate(projectFilePath, allowAutoRestore, projectId)); + _queue.Post(new ProjectToUpdate(projectFilePath, allowAutoRestore, projectId, changeTriggerFilePath)); } public async Task WaitForQueueEmptyAsync() @@ -262,7 +264,7 @@ private void ProcessQueue(CancellationToken cancellationToken) { foreach (var project in projectList) { - UpdateProject(project.FilePath); + UpdateProject(project.FilePath, project.ChangeTriggerPath); // Fire loaded events if (project.LoadedEventArgs != null) @@ -382,7 +384,7 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) // as "updates". We should properly remove projects that are deleted. _fileSystemWatcher.Watch(projectFileInfo.FilePath, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: true, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: true, projectFileInfo.ProjectIdInfo, file); }); if (_workspace.EditorConfigEnabled) @@ -390,7 +392,7 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) // Watch beneath the Project folder for changes to .editorconfig files. _fileSystemWatcher.Watch(".editorconfig", (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); // Watch in folders above the Project folder for changes to .editorconfig files. @@ -404,7 +406,7 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) _fileSystemWatcher.Watch(Path.Combine(parentPath, ".editorconfig"), (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); } } @@ -413,7 +415,7 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) { _fileSystemWatcher.Watch(projectFileInfo.RuleSet.FilePath, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); } @@ -421,7 +423,7 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) { _fileSystemWatcher.Watch(projectFileInfo.ProjectAssetsFile, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); var restoreDirectory = Path.GetDirectoryName(projectFileInfo.ProjectAssetsFile); @@ -432,22 +434,22 @@ private void WatchProjectFiles(ProjectFileInfo projectFileInfo) _fileSystemWatcher.Watch(nugetCacheFile, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); _fileSystemWatcher.Watch(nugetPropsFile, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); _fileSystemWatcher.Watch(nugetTargetsFile, (file, changeType) => { - QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo); + QueueProjectUpdate(projectFileInfo.FilePath, allowAutoRestore: false, projectFileInfo.ProjectIdInfo, file); }); } } - private void UpdateProject(string projectFilePath) + private void UpdateProject(string projectFilePath, string changeTriggerFilePath) { if (!_projectFiles.TryGetValue(projectFilePath, out var projectFileInfo)) { @@ -462,6 +464,15 @@ private void UpdateProject(string projectFilePath) return; } + // if the update was triggered by a change to an editorconfig file, only reload that analyzer config file + // this will propagata a reanalysis of the project + if (changeTriggerFilePath != null && changeTriggerFilePath.ToLowerInvariant().EndsWith(".editorconfig")) + { + UpdateAnalyzerConfigFile(project, changeTriggerFilePath); + return; + } + + // for other update triggers, perform a full check of all options UpdateSourceFiles(project, projectFileInfo.SourceFiles); UpdateParseOptions(project, projectFileInfo.LanguageVersion, projectFileInfo.PreprocessorSymbolNames, !string.IsNullOrWhiteSpace(projectFileInfo.DocumentationFile)); UpdateProjectReferences(project, projectFileInfo.ProjectReferences); @@ -487,7 +498,7 @@ private void UpdateCompilationOptions(Project project, ProjectFileInfo projectFi if (newCompilationOptions != existingCompilationOptions) { _workspace.UpdateCompilationOptionsForProject(project.Id, newCompilationOptions); - _logger.LogDebug("Updated project compilation options on project {project.Id}."); + _logger.LogDebug($"Updated project compilation options on project {project.Name}."); } } } @@ -545,6 +556,31 @@ private void UpdateAdditionalFiles(Project project, IList additionalFile } } + private void UpdateAnalyzerConfigFile(Project project, string analyzerConfigFile) + { + if (!_workspace.EditorConfigEnabled) + { + _logger.LogDebug($".editorconfig files were configured by the project {project.Name} but will not be respected because the feature is switched off in OmniSharp. Enable .editorconfig support in OmniSharp to take advantage of them."); + return; + } + + var currentAnalyzerConfigDocument = project.AnalyzerConfigDocuments.FirstOrDefault(x => x.FilePath.Equals(analyzerConfigFile)); + if (currentAnalyzerConfigDocument == null) + { + _logger.LogDebug($"The change was reported in {analyzerConfigFile} but it doesn't belong to any project."); + return; + } + + if (!File.Exists(analyzerConfigFile)) + { + _logger.LogWarning($"The change was reported in {analyzerConfigFile} but it doesn't exist on disk."); + return; + } + + _workspace.ReloadAnalyzerConfigDocument(currentAnalyzerConfigDocument.Id, analyzerConfigFile); + _logger.LogDebug($"Reloaded {analyzerConfigFile} in project {project.Name}."); + } + private void UpdateAnalyzerConfigFiles(Project project, IList analyzerConfigFiles) { if (!_workspace.EditorConfigEnabled) @@ -556,6 +592,7 @@ private void UpdateAnalyzerConfigFiles(Project project, IList analyzerCo var currentAnalyzerConfigDocuments = project.AnalyzerConfigDocuments; foreach (var document in currentAnalyzerConfigDocuments) { + _logger.LogDebug($".editorconfig file '{document.Name}' removed from project {project.Name}"); _workspace.RemoveAnalyzerConfigDocument(document.Id); } @@ -563,12 +600,12 @@ private void UpdateAnalyzerConfigFiles(Project project, IList analyzerCo { if (File.Exists(file)) { - _logger.LogDebug($".editorconfig file for project {project.Name}: {file}"); _workspace.AddAnalyzerConfigDocument(project.Id, file); + _logger.LogDebug($".editorconfig file '{file}' added for project {project.Name}"); } else { - _logger.LogDebug($".editorconfig file for project {project.Name}: {file} was expected but not found on disk."); + _logger.LogWarning($".editorconfig file '{file}' for project {project.Name} was expected but not found on disk."); } } } diff --git a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs index a6d0933a15..23f9297353 100644 --- a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs +++ b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs @@ -173,15 +173,15 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs changeEv _logger.LogDebug($"Tried to remove non existent document from analysis, document: {changeEvent.DocumentId}"); } break; + case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: + _logger.LogDebug($"Analyzer config document {changeEvent.DocumentId} changed, which triggered re-analysis of project {changeEvent.ProjectId}."); + QueueForAnalysis(_workspace.CurrentSolution.GetProject(changeEvent.ProjectId).Documents.Select(x => x.Id).ToImmutableArray(), AnalyzerWorkType.Background); + break; case WorkspaceChangeKind.ProjectAdded: case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: - // at the moment we remove and re-add analyzer documents when project update is requested - // therefore it is enough to just listen to "AnalyzerConfigDocumentAdded" event to trigger re-analysis - case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: _logger.LogDebug($"Project {changeEvent.ProjectId} updated, reanalyzing its diagnostics."); - var projectDocumentIds = _workspace.CurrentSolution.GetProject(changeEvent.ProjectId).Documents.Select(x => x.Id).ToImmutableArray(); - QueueForAnalysis(projectDocumentIds, AnalyzerWorkType.Background); + QueueForAnalysis(_workspace.CurrentSolution.GetProject(changeEvent.ProjectId).Documents.Select(x => x.Id).ToImmutableArray(), AnalyzerWorkType.Background); break; case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionChanged: diff --git a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs index bbf6ae4064..643f58cb2d 100644 --- a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs +++ b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs @@ -556,6 +556,12 @@ public void AddAnalyzerConfigDocument(ProjectId projectId, string filePath) OnAnalyzerConfigDocumentAdded(documentInfo); } + public void ReloadAnalyzerConfigDocument(DocumentId documentId, string filePath) + { + var loader = new OmniSharpTextLoader(filePath); + OnAnalyzerConfigDocumentTextLoaderChanged(documentId, loader); + } + public void RemoveAdditionalDocument(DocumentId documentId) { OnAdditionalDocumentRemoved(documentId); From 76f990b0c54cb362c96f1fe122e4b21d43e99d35 Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 22:03:14 +0100 Subject: [PATCH 7/8] improved log message --- src/OmniSharp.MSBuild/ProjectManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index 44a051465b..e72da753c6 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -578,7 +578,7 @@ private void UpdateAnalyzerConfigFile(Project project, string analyzerConfigFile } _workspace.ReloadAnalyzerConfigDocument(currentAnalyzerConfigDocument.Id, analyzerConfigFile); - _logger.LogDebug($"Reloaded {analyzerConfigFile} in project {project.Name}."); + _logger.LogDebug($"Reloaded {currentAnalyzerConfigDocument.Id} from {analyzerConfigFile} in project {project.Name}."); } private void UpdateAnalyzerConfigFiles(Project project, IList analyzerConfigFiles) From 5fe1264af7206b321b2701b21c1528fca2f3176f Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 24 Nov 2020 22:20:04 +0100 Subject: [PATCH 8/8] added a test for analyzer preservation --- .../ProjectWithAnalyzersTests.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs b/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs index 309405bb8d..187ca7b789 100644 --- a/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs @@ -122,6 +122,32 @@ public async Task WhenProjectEditorConfigIsChangedThenAnalyzerConfigurationUpdat } } + [Fact] + public async Task WhenProjectChangesAnalyzerConfigurationIsPreserved() + { + var emitter = new ProjectLoadTestEventEmitter(); + + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ProjectWithAnalyzersAndEditorConfig")) + using (var host = CreateMSBuildTestHost( + testProject.Directory, + emitter.AsExportDescriptionProvider(LoggerFactory), + TestHelpers.GetConfigurationDataWithAnalyzerConfig(roslynAnalyzersEnabled: true, editorConfigEnabled: true))) + { + var initialProject = host.Workspace.CurrentSolution.Projects.Single(); + var firstDiagnosticsSet = await host.RequestCodeCheckAsync(Path.Combine(testProject.Directory, "Program.cs")); + Assert.NotEmpty(firstDiagnosticsSet.QuickFixes); + Assert.Contains(firstDiagnosticsSet.QuickFixes.OfType(), x => x.Id == "IDE0005" && x.LogLevel == "Error"); + + // report reloading of a project + await NotifyFileChanged(host, initialProject.FilePath); + emitter.WaitForProjectUpdate(); + + var secondDiagnosticsSet = await host.RequestCodeCheckAsync(Path.Combine(testProject.Directory, "Program.cs")); + Assert.NotEmpty(secondDiagnosticsSet.QuickFixes); + Assert.Contains(secondDiagnosticsSet.QuickFixes.OfType(), x => x.Id == "IDE0005" && x.LogLevel == "Error"); + } + } + [Fact] public async Task WhenProjectIsLoadedThenItContainsAnalyzerConfigurationFromParentFolder() {