diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs index 4f2bd13e97f3cb8e1744c42e58c25474e0da90f9..1b00adf6cb3e714cb419079191dbcb348386b361 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; @@ -12,6 +13,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -80,7 +82,26 @@ private enum ConfigurationKind /// . /// public static Task ConfigureSeverityAsync( - string severity, + ReportDiagnostic severity, + Diagnostic diagnostic, + Project project, + CancellationToken cancellationToken) + { + if (severity == ReportDiagnostic.Default) + { + severity = diagnostic.DefaultSeverity.ToReportDiagnostic(); + } + + return ConfigureSeverityAsync(severity.ToEditorConfigString(), diagnostic, project, cancellationToken); + } + + /// + /// Updates or adds an .editorconfig to the given + /// so that the severity of the given is configured to be the given + /// . + /// + public static Task ConfigureSeverityAsync( + string editorConfigSeverity, Diagnostic diagnostic, Project project, CancellationToken cancellationToken) @@ -93,12 +114,12 @@ private enum ConfigurationKind if (!codeStyleOptionValues.IsEmpty) { return ConfigureCodeStyleOptionsAsync( - codeStyleOptionValues.Select(t => (t.optionName, t.currentOptionValue, severity)), + codeStyleOptionValues.Select(t => (t.optionName, t.currentOptionValue, editorConfigSeverity)), diagnostic, project, configurationKind: ConfigurationKind.Severity, cancellationToken); } else { - updater = new ConfigurationUpdater(optionNameOpt: null, newOptionValueOpt: null, severity, + updater = new ConfigurationUpdater(optionNameOpt: null, newOptionValueOpt: null, editorConfigSeverity, configurationKind: ConfigurationKind.Severity, diagnostic, project, cancellationToken); return updater.ConfigureAsync(); } @@ -143,16 +164,14 @@ private enum ConfigurationKind private async Task ConfigureAsync() { - var solution = _project.Solution; - // Find existing .editorconfig or generate a new one if none exists. - var editorConfigDocument = FindOrGenerateEditorConfig(solution); + var editorConfigDocument = FindOrGenerateEditorConfig(); if (editorConfigDocument == null) { - return solution; + return _project.Solution; } - solution = editorConfigDocument.Project.Solution; + var solution = editorConfigDocument.Project.Solution; var headers = new Dictionary(); var originalText = await editorConfigDocument.GetTextAsync(_cancellationToken).ConfigureAwait(false); @@ -165,52 +184,15 @@ private async Task ConfigureAsync() : solution; } - private AnalyzerConfigDocument FindOrGenerateEditorConfig(Solution solution) + private AnalyzerConfigDocument FindOrGenerateEditorConfig() { - if (_project.AnalyzerConfigDocuments.Any()) - { - var diagnosticFilePath = PathUtilities.GetDirectoryName(_diagnostic.Location.SourceTree?.FilePath ?? _project.FilePath); - if (!PathUtilities.IsAbsolute(diagnosticFilePath)) - { - return null; - } - - // Currently, we use a simple heuristic to find existing .editorconfig file. - // We start from the directory of the source file where the diagnostic was reported and walk up - // the directory tree to find an .editorconfig file. - // In future, we might change this algorithm, or allow end users to customize it based on options. - - var bestPath = string.Empty; - AnalyzerConfigDocument bestAnalyzerConfigDocument = null; - foreach (var analyzerConfigDocument in _project.AnalyzerConfigDocuments) - { - var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigDocument.FilePath); - if (diagnosticFilePath.StartsWith(analyzerConfigDirectory) && - analyzerConfigDirectory.Length > bestPath.Length) - { - bestPath = analyzerConfigDirectory; - bestAnalyzerConfigDocument = analyzerConfigDocument; - } - } - - if (bestAnalyzerConfigDocument != null) - { - return bestAnalyzerConfigDocument; - } - } - - // Did not find any existing .editorconfig, so create one at root of the project. - if (!PathUtilities.IsAbsolute(_project.FilePath)) + var analyzerConfigPath = _project.TryGetAnalyzerConfigPathForDiagnosticConfiguration(_diagnostic); + if (analyzerConfigPath == null) { return null; } - var projectFilePath = PathUtilities.GetDirectoryName(_project.FilePath); - var newEditorConfigPath = PathUtilities.CombineAbsoluteAndRelativePaths(projectFilePath, ".editorconfig"); - var id = DocumentId.CreateNewId(_project.Id); - var documentInfo = DocumentInfo.Create(id, ".editorconfig", filePath: newEditorConfigPath); - var newSolution = solution.AddAnalyzerConfigDocuments(ImmutableArray.Create(documentInfo)); - return newSolution.GetProject(_project.Id).GetAnalyzerConfigDocument(id); + return _project.GetOrCreateAnalyzerConfigDocument(analyzerConfigPath); } private static ImmutableArray<(string optionName, string currentOptionValue, string currentSeverity)> GetCodeStyleOptionValuesForDiagnostic( diff --git a/src/VisualStudio/Core/Def/Commands.vsct b/src/VisualStudio/Core/Def/Commands.vsct index 03bf54aa4b54e6620c65a28b15753a5cac4f41c2..a6d7ce38d45400dd8de4bf4d545dee947f2bd09a 100644 --- a/src/VisualStudio/Core/Def/Commands.vsct +++ b/src/VisualStudio/Core/Def/Commands.vsct @@ -194,18 +194,18 @@ @@ -346,10 +346,10 @@ - Set Rule Set Severity - Set Rule Set Severity - Set Rule Set Severity - Set Rule Set Severity + Set severity + Set severity + Set severity + Set severity diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf index e391a4afb6f54fe73278da914fc1c4f1d045f9da..fe6cfbe4dfd0be9007dbd3085ce2402f73f57bd2 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf @@ -148,13 +148,13 @@ - &Info - &Informace + &Suggestion + &Informace - Info - Informace + Suggestion + Informace @@ -163,13 +163,13 @@ - &Hidden - &Skryté + &Silent + &Skryté - Hidden - Skryté + Silent + Skryté @@ -333,18 +333,18 @@ - Set Rule Set Severity - Nastavit závažnost sady pravidel + Set severity + Nastavit závažnost sady pravidel - Set Rule Set Severity - Nastavit závažnost sady pravidel + Set severity + Nastavit závažnost sady pravidel - Set Rule Set Severity - Nastavit závažnost sady pravidel + Set severity + Nastavit závažnost sady pravidel diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf index 59304e23d70105bd0a10399ab5dd28f50e098fda..85aac5c4b16a8f6677cab94e3ab1f311de4a9aff 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf @@ -148,13 +148,13 @@ - &Info - &Info + &Suggestion + &Info - Info - Info + Suggestion + Info @@ -163,13 +163,13 @@ - &Hidden - &Ausgeblendet + &Silent + &Ausgeblendet - Hidden - Ausgeblendet + Silent + Ausgeblendet @@ -333,18 +333,18 @@ - Set Rule Set Severity - Schweregrad für Regelsatz festlegen + Set severity + Schweregrad für Regelsatz festlegen - Set Rule Set Severity - Schweregrad für Regelsatz festlegen + Set severity + Schweregrad für Regelsatz festlegen - Set Rule Set Severity - Schweregrad für Regelsatz festlegen + Set severity + Schweregrad für Regelsatz festlegen diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf index fdf90bd48283823363568218d70c43470ea1ed4c..86d27bdf7ec520d28599cec7f0a768cfaeb927c2 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf @@ -148,13 +148,13 @@ - &Info - &Información + &Suggestion + &Información - Info - Información + Suggestion + Información @@ -163,13 +163,13 @@ - &Hidden - &Oculto + &Silent + &Oculto - Hidden - Oculto + Silent + Oculto @@ -333,18 +333,18 @@ - Set Rule Set Severity - Configurar gravedad del conjunto de reglas + Set severity + Configurar gravedad del conjunto de reglas - Set Rule Set Severity - Configurar gravedad del conjunto de reglas + Set severity + Configurar gravedad del conjunto de reglas - Set Rule Set Severity - Configurar gravedad del conjunto de reglas + Set severity + Configurar gravedad del conjunto de reglas diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf index cc9c8a5bb0217ad45fca508fc89d9e0dad038649..c2f87a7624f799bdf99d3c1a6e14028716883bfa 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf @@ -148,13 +148,13 @@ - &Info - &Informations + &Suggestion + &Informations - Info - Info + Suggestion + Info @@ -163,13 +163,13 @@ - &Hidden - &Masqué + &Silent + &Masqué - Hidden - Masqué + Silent + Masqué @@ -333,18 +333,18 @@ - Set Rule Set Severity - Définir la gravité de l'ensemble de règles + Set severity + Définir la gravité de l'ensemble de règles - Set Rule Set Severity - Définir la gravité de l'ensemble de règles + Set severity + Définir la gravité de l'ensemble de règles - Set Rule Set Severity - Définir la gravité de l'ensemble de règles + Set severity + Définir la gravité de l'ensemble de règles diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf index 196ee12a3fe0f907ba9304e9eaa648b0dc9cf96e..c30f71d2b3b5d6daa397fc836e59b1f0d942660b 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf @@ -148,13 +148,13 @@ - &Info - In&formazioni + &Suggestion + In&formazioni - Info - Info + Suggestion + Info @@ -163,13 +163,13 @@ - &Hidden - &Nascosto + &Silent + &Nascosto - Hidden - Nascosto + Silent + Nascosto @@ -333,18 +333,18 @@ - Set Rule Set Severity - Imposta gravit?? set di regole + Set severity + Imposta gravit?? set di regole - Set Rule Set Severity - Imposta gravit?? set di regole + Set severity + Imposta gravit?? set di regole - Set Rule Set Severity - Imposta gravit?? set di regole + Set severity + Imposta gravit?? set di regole diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf index 5c0becfc89c698c2da80a7edd8971d6c0b0db432..59bf627c2f32a6b17985edb2a57f4ba147b3de14 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf @@ -148,13 +148,13 @@ - &Info - 情報(&I) + &Suggestion + 情報(&I) - Info - 情報 + Suggestion + 情報 @@ -163,13 +163,13 @@ - &Hidden - 非表示(&H) + &Silent + 非表示(&H) - Hidden - 非表示 + Silent + 非表示 @@ -333,18 +333,18 @@ - Set Rule Set Severity - ルール セットの重要度を設定 + Set severity + ルール セットの重要度を設定 - Set Rule Set Severity - ルール セットの重要度を設定 + Set severity + ルール セットの重要度を設定 - Set Rule Set Severity - ルール セットの重要度を設定 + Set severity + ルール セットの重要度を設定 diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf index c1af6a37a7337fc91ec238b23de2ad2a79b16777..3874662f5e8997eb637b9fb85eb197b5d261337f 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf @@ -148,13 +148,13 @@ - &Info - 정보(&I) + &Suggestion + 정보(&I) - Info - 정보 + Suggestion + 정보 @@ -163,13 +163,13 @@ - &Hidden - 숨김(&H) + &Silent + 숨김(&H) - Hidden - 숨김 + Silent + 숨김 @@ -333,18 +333,18 @@ - Set Rule Set Severity - 규칙 집합 심각도 설정 + Set severity + 규칙 집합 심각도 설정 - Set Rule Set Severity - 규칙 집합 심각도 설정 + Set severity + 규칙 집합 심각도 설정 - Set Rule Set Severity - 규칙 집합 심각도 설정 + Set severity + 규칙 집합 심각도 설정 diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf index f91d04c66b58ed1f5e43d4c2fc79f245b306294a..67b1ee542c5f88af3d15531400cddad85a62a3e5 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf @@ -148,13 +148,13 @@ - &Info - &Informacje + &Suggestion + &Informacje - Info - Informacje + Suggestion + Informacje @@ -163,13 +163,13 @@ - &Hidden - &Ukryte + &Silent + &Ukryte - Hidden - Ukryty + Silent + Ukryty @@ -333,18 +333,18 @@ - Set Rule Set Severity - Ustaw ważność zestawu reguł + Set severity + Ustaw ważność zestawu reguł - Set Rule Set Severity - Ustaw ważność zestawu reguł + Set severity + Ustaw ważność zestawu reguł - Set Rule Set Severity - Ustaw ważność zestawu reguł + Set severity + Ustaw ważność zestawu reguł diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf index 763e4b12265453b0b2e57ef79c1b4acafb340b3c..2d1c9d8a5c2804736b1cd9fc754bd6e1bba2b9fb 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf @@ -148,13 +148,13 @@ - &Info - &Informações + &Suggestion + &Informações - Info - Informação + Suggestion + Informação @@ -163,13 +163,13 @@ - &Hidden - &Oculto + &Silent + &Oculto - Hidden - Oculto + Silent + Oculto @@ -333,18 +333,18 @@ - Set Rule Set Severity - Definir Regra Definir Gravidade + Set severity + Definir Regra Definir Gravidade - Set Rule Set Severity - Definir Regra Definir Gravidade + Set severity + Definir Regra Definir Gravidade - Set Rule Set Severity - Definir Regra Definir Gravidade + Set severity + Definir Regra Definir Gravidade diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf index f99b50607e7ff307f8ad3ecd8896ce6a57480a1d..cc05785fca87a0fa323ff3c6a247efc614b82830 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf @@ -148,13 +148,13 @@ - &Info - &Информация + &Suggestion + &Информация - Info - Информация + Suggestion + Информация @@ -163,13 +163,13 @@ - &Hidden - &Скрытый + &Silent + &Скрытый - Hidden - Скрытый + Silent + Скрытый @@ -333,18 +333,18 @@ - Set Rule Set Severity - Установить серьезность набора правил + Set severity + Установить серьезность набора правил - Set Rule Set Severity - Установить серьезность набора правил + Set severity + Установить серьезность набора правил - Set Rule Set Severity - Установить серьезность набора правил + Set severity + Установить серьезность набора правил diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf index 8acbf37068e353d9637decd4eea2b999e25e80bd..4a7fcc99e7250e3ae1c634e34d4195fcb718adea 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf @@ -148,13 +148,13 @@ - &Info - &Bilgi + &Suggestion + &Bilgi - Info - Bilgi + Suggestion + Bilgi @@ -163,13 +163,13 @@ - &Hidden - &Gizli + &Silent + &Gizli - Hidden - Gizli + Silent + Gizli @@ -333,18 +333,18 @@ - Set Rule Set Severity - Kural Kümesi Önem Derecesini Ayarla + Set severity + Kural Kümesi Önem Derecesini Ayarla - Set Rule Set Severity - Kural Kümesi Önem Derecesini Ayarla + Set severity + Kural Kümesi Önem Derecesini Ayarla - Set Rule Set Severity - Kural Kümesi Önem Derecesini Ayarla + Set severity + Kural Kümesi Önem Derecesini Ayarla diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf index dee9f3ad633c9998c6f5513033e68e593f30dce7..121b78e2110f1b400eba7a131fe4aad5d6415128 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf @@ -148,13 +148,13 @@ - &Info - 信息(&I) + &Suggestion + 信息(&I) - Info - 信息 + Suggestion + 信息 @@ -163,13 +163,13 @@ - &Hidden - 隐藏(&H) + &Silent + 隐藏(&H) - Hidden - 隐藏 + Silent + 隐藏 @@ -333,18 +333,18 @@ - Set Rule Set Severity - 设置规则集严重性 + Set severity + 设置规则集严重性 - Set Rule Set Severity - 设置规则集严重性 + Set severity + 设置规则集严重性 - Set Rule Set Severity - 设置规则集严重性 + Set severity + 设置规则集严重性 diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf index 06f3fafccc06bd048fd5a185acb801fd1f024e33..969b0afa9d1d861e1868e7904e67ad36809ea056 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf @@ -148,13 +148,13 @@ - &Info - 資訊(&I) + &Suggestion + 資訊(&I) - Info - 資訊 + Suggestion + 資訊 @@ -163,13 +163,13 @@ - &Hidden - 隱藏(&H) + &Silent + 隱藏(&H) - Hidden - 隱藏 + Silent + 隱藏 @@ -333,18 +333,18 @@ - Set Rule Set Severity - 設定規則集合嚴重性 + Set severity + 設定規則集合嚴重性 - Set Rule Set Severity - 設定規則集合嚴重性 + Set severity + 設定規則集合嚴重性 - Set Rule Set Severity - 設定規則集合嚴重性 + Set severity + 設定規則集合嚴重性 diff --git a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs index bc5cefc2dde040b3aaa762491189ba0f07d9c7b0..3b8b20a9cb94abda58d135360edca5ff6c7d8f29 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; @@ -12,6 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.CodeAnalysis; using Microsoft.VisualStudio.ComponentModelHost; @@ -22,6 +24,7 @@ using Microsoft.VisualStudio.Shell.Interop; using Roslyn.Utilities; using VSLangProj140; +using Project = Microsoft.CodeAnalysis.Project; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer { @@ -172,7 +175,10 @@ private bool ShouldShowAnalyzerContextMenu(IEnumerable items) private void UpdateAnalyzerContextMenu() { - _removeMenuItem.Enabled = _allowProjectSystemOperations; + if (_removeMenuItem != null) + { + _removeMenuItem.Enabled = _allowProjectSystemOperations; + } } public IContextMenuController DiagnosticContextMenuController @@ -265,28 +271,25 @@ private void UpdateSeverityMenuItemsChecked() foreach (var group in groups) { - var ruleSetPath = workspace.TryGetRuleSetPathForProject(group.Key); + var project = workspace.CurrentSolution.GetProject(group.Key); + if (project == null) + { + continue; + } - if (ruleSetPath != null) + var analyzerConfigSpecificDiagnosticOptions = project.GetAnalyzerConfigSpecialDiagnosticOptions(); + + foreach (var diagnosticItem in group) { - var ruleSetManager = workspace.Services.GetRequiredService(); - using (var ruleSet = ruleSetManager.GetOrCreateRuleSet(ruleSetPath)) + var severity = ReportDiagnostic.Default; + if (project.CompilationOptions.SpecificDiagnosticOptions.ContainsKey(diagnosticItem.Descriptor.Id) || + analyzerConfigSpecificDiagnosticOptions.ContainsKey(diagnosticItem.Descriptor.Id)) { - var specificOptions = ruleSet.Target.Value.GetSpecificDiagnosticOptions(); - - foreach (var diagnosticItem in group) - { - if (specificOptions.TryGetValue(diagnosticItem.Descriptor.Id, out var ruleSetSeverity)) - { - selectedItemSeverities.Add(ruleSetSeverity); - } - else - { - // The rule has no setting. - selectedItemSeverities.Add(ReportDiagnostic.Default); - } - } + // Severity is overridden by end user. + severity = diagnosticItem.Descriptor.GetEffectiveSeverity(project.CompilationOptions, analyzerConfigSpecificDiagnosticOptions); } + + selectedItemSeverities.Add(severity); } } @@ -320,11 +323,6 @@ private void UpdateSeverityMenuItemsChecked() } } - private bool AnyDiagnosticsWithSeverity(ReportDiagnostic severity) - { - return _tracker.SelectedDiagnosticItems.Any(item => item.EffectiveSeverity == severity); - } - private void UpdateSeverityMenuItemsEnabled() { var configurable = !_tracker.SelectedDiagnosticItems.Any(item => item.Descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable)); @@ -421,18 +419,46 @@ private void SetSeverityHandler(object sender, EventArgs args) var projectId = selectedDiagnostic.ProjectId; var pathToRuleSet = workspace.TryGetRuleSetPathForProject(projectId); - if (pathToRuleSet == null) + var project = workspace.CurrentSolution.GetProject(projectId); + var pathToAnalyzerConfigDoc = project?.TryGetAnalyzerConfigPathForProjectConfiguration(); + + if (pathToRuleSet == null && pathToAnalyzerConfigDoc == null) { SendUnableToUpdateRuleSetNotification(workspace, SolutionExplorerShim.No_rule_set_file_is_specified_or_the_file_does_not_exist); continue; } + var componentModel = (IComponentModel)_serviceProvider.GetService(typeof(SComponentModel)); + var waitIndicator = componentModel.GetService(); + try { var envDteProject = workspace.TryGetDTEProject(projectId); - if (SdkUiUtilities.IsBuiltInRuleSet(pathToRuleSet, _serviceProvider)) + if (pathToRuleSet == null || SdkUiUtilities.IsBuiltInRuleSet(pathToRuleSet, _serviceProvider)) { + // If project is using the default built-in ruleset or no ruleset, then prefer .editorconfig for severity configuration. + if (pathToAnalyzerConfigDoc != null) + { + waitIndicator.Wait( + title: SolutionExplorerShim.Updating_severity, + message: SolutionExplorerShim.Updating_severity, + allowCancel: true, + action: c => + { + var newSolution = selectedDiagnostic.GetSolutionWithUpdatedAnalyzerConfigSeverityAsync(selectedAction.Value, project, c.CancellationToken).WaitAndGetResult(c.CancellationToken); + _workspace.TryApplyChanges(newSolution, c.ProgressTracker); + }); + continue; + } + + // Otherwise, fall back to using ruleset. + if (pathToRuleSet == null) + { + SendUnableToUpdateRuleSetNotification(workspace, SolutionExplorerShim.No_rule_set_file_is_specified_or_the_file_does_not_exist); + continue; + } + pathToRuleSet = CreateCopyOfRuleSetForProject(pathToRuleSet, envDteProject); if (pathToRuleSet == null) { @@ -444,8 +470,6 @@ private void SetSeverityHandler(object sender, EventArgs args) fileInfo.IsReadOnly = false; } - var componentModel = (IComponentModel)_serviceProvider.GetService(typeof(SComponentModel)); - var waitIndicator = componentModel.GetService(); waitIndicator.Wait( title: SolutionExplorerShim.Rule_Set, message: string.Format(SolutionExplorerShim.Checking_out_0_for_editing, Path.GetFileName(pathToRuleSet)), @@ -458,7 +482,7 @@ private void SetSeverityHandler(object sender, EventArgs args) } }); - selectedDiagnostic.SetSeverity(selectedAction.Value, pathToRuleSet); + selectedDiagnostic.SetRuleSetSeverity(selectedAction.Value, pathToRuleSet); } catch (Exception e) { diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs index 1f74343f4e5dbabb62d7ed3c68bd287a713397c9..1bdc2778e105e8653b6388fc09c670013eb6d95d 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs @@ -2,13 +2,17 @@ using System; using System.ComponentModel; +using System.Threading; +using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes.Configuration; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer { @@ -106,12 +110,7 @@ private void NotifyPropertyChanged(string propertyName) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - internal void SetSeverity(ReportDiagnostic value, string pathToRuleSet) - { - UpdateRuleSetFile(pathToRuleSet, value); - } - - private void UpdateRuleSetFile(string pathToRuleSet, ReportDiagnostic value) + internal void SetRuleSetSeverity(ReportDiagnostic value, string pathToRuleSet) { var ruleSetDocument = XDocument.Load(pathToRuleSet); @@ -119,5 +118,12 @@ private void UpdateRuleSetFile(string pathToRuleSet, ReportDiagnostic value) ruleSetDocument.Save(pathToRuleSet); } + + internal Task GetSolutionWithUpdatedAnalyzerConfigSeverityAsync(ReportDiagnostic value, Project project, CancellationToken cancellationToken) + { + var effectiveSeverity = value.ToDiagnosticSeverity() ?? _descriptor.DefaultSeverity; + var diagnostic = Diagnostic.Create(_descriptor, Location.None, effectiveSeverity, additionalLocations: null, properties: null); + return ConfigurationUpdater.ConfigureSeverityAsync(value, diagnostic, project, cancellationToken); + } } } diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs index ecf2ffc145c74b1c8628542542c2928e07438f0d..cafa659fda110d8accf8b23a4ddbf67f9f9bfa6f 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs @@ -8,35 +8,35 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer { - using Workspace = Microsoft.CodeAnalysis.Workspace; - internal abstract partial class BaseDiagnosticItemSource : IAttachedCollectionSource { - protected static readonly DiagnosticDescriptorComparer s_comparer = new DiagnosticDescriptorComparer(); - - protected readonly Workspace _workspace; - protected readonly ProjectId _projectId; - protected readonly IAnalyzersCommandHandler _commandHandler; - protected readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; + private static readonly DiagnosticDescriptorComparer s_comparer = new DiagnosticDescriptorComparer(); - protected BulkObservableCollection _diagnosticItems; + private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; - protected ReportDiagnostic _generalDiagnosticOption; - protected ImmutableDictionary _specificDiagnosticOptions; + private BulkObservableCollection _diagnosticItems; + private ReportDiagnostic _generalDiagnosticOption; + private ImmutableDictionary _specificDiagnosticOptions; + private ImmutableDictionary _analyzerConfigSpecificDiagnosticOptions; public BaseDiagnosticItemSource(Workspace workspace, ProjectId projectId, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService) { - _workspace = workspace; - _projectId = projectId; - _commandHandler = commandHandler; + Workspace = workspace; + ProjectId = projectId; + CommandHandler = commandHandler; _diagnosticAnalyzerService = diagnosticAnalyzerService; } + public Workspace Workspace { get; } + public ProjectId ProjectId { get; } + protected IAnalyzersCommandHandler CommandHandler { get; } + public abstract AnalyzerReference AnalyzerReference { get; } protected abstract BaseDiagnosticItem CreateItem(DiagnosticDescriptor diagnostic, ReportDiagnostic effectiveSeverity); @@ -56,7 +56,7 @@ public bool HasItems return false; } - var project = _workspace.CurrentSolution.GetProject(_projectId); + var project = Workspace.CurrentSolution.GetProject(ProjectId); return AnalyzerReference.GetAnalyzers(project.Language).Length > 0; } } @@ -67,14 +67,15 @@ public IEnumerable Items { if (_diagnosticItems == null) { - var project = _workspace.CurrentSolution.GetProject(_projectId); + var project = Workspace.CurrentSolution.GetProject(ProjectId); _generalDiagnosticOption = project.CompilationOptions.GeneralDiagnosticOption; _specificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions; + _analyzerConfigSpecificDiagnosticOptions = project.GetAnalyzerConfigSpecialDiagnosticOptions(); _diagnosticItems = new BulkObservableCollection(); - _diagnosticItems.AddRange(GetDiagnosticItems(project.Language, project.CompilationOptions)); + _diagnosticItems.AddRange(GetDiagnosticItems(project.Language, project.CompilationOptions, _analyzerConfigSpecificDiagnosticOptions)); - _workspace.WorkspaceChanged += OnWorkspaceChangedLookForOptionsChanges; + Workspace.WorkspaceChanged += OnWorkspaceChangedLookForOptionsChanges; } Logger.Log( @@ -85,7 +86,7 @@ public IEnumerable Items } } - private IEnumerable GetDiagnosticItems(string language, CompilationOptions options) + private IEnumerable GetDiagnosticItems(string language, CompilationOptions options, ImmutableDictionary analyzerConfigSpecificDiagnosticOptions) { // Within an analyzer assembly, an individual analyzer may report multiple different diagnostics // with the same ID. Or, multiple analyzers may report diagnostics with the same ID. Or a @@ -103,7 +104,7 @@ private IEnumerable GetDiagnosticItems(string language, Comp .Select(g => { var selectedDiagnostic = g.OrderBy(d => d, s_comparer).First(); - var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity(options); + var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity(options, analyzerConfigSpecificDiagnosticOptions); return CreateItem(selectedDiagnostic, effectiveSeverity); }); } @@ -114,35 +115,57 @@ private void OnWorkspaceChangedLookForOptionsChanges(object sender, WorkspaceCha e.Kind == WorkspaceChangeKind.SolutionReloaded || e.Kind == WorkspaceChangeKind.SolutionRemoved) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; } - else if (e.ProjectId == _projectId) + else if (e.ProjectId == ProjectId) { if (e.Kind == WorkspaceChangeKind.ProjectRemoved) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; } else if (e.Kind == WorkspaceChangeKind.ProjectChanged) { - var project = e.NewSolution.GetProject(_projectId); - var newGeneralDiagnosticOption = project.CompilationOptions.GeneralDiagnosticOption; - var newSpecificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions; + OnProjectConfigurationChanged(); + } + else if (e.DocumentId != null) + { + switch (e.Kind) + { + case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: + case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: + case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: + case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: + OnProjectConfigurationChanged(); + break; + } + } + } + + return; + + // Local functions. + void OnProjectConfigurationChanged() + { + var project = e.NewSolution.GetProject(ProjectId); + var newGeneralDiagnosticOption = project.CompilationOptions.GeneralDiagnosticOption; + var newSpecificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions; + var newAnalyzerConfigSpecificDiagnosticOptions = project.GetAnalyzerConfigSpecialDiagnosticOptions(); + + if (newGeneralDiagnosticOption != _generalDiagnosticOption || + !object.ReferenceEquals(newSpecificDiagnosticOptions, _specificDiagnosticOptions) || + !object.ReferenceEquals(newAnalyzerConfigSpecificDiagnosticOptions, _analyzerConfigSpecificDiagnosticOptions)) + { + _generalDiagnosticOption = newGeneralDiagnosticOption; + _specificDiagnosticOptions = newSpecificDiagnosticOptions; + _analyzerConfigSpecificDiagnosticOptions = newAnalyzerConfigSpecificDiagnosticOptions; - if (newGeneralDiagnosticOption != _generalDiagnosticOption || - !object.ReferenceEquals(newSpecificDiagnosticOptions, _specificDiagnosticOptions)) + foreach (var item in _diagnosticItems) { - _generalDiagnosticOption = newGeneralDiagnosticOption; - _specificDiagnosticOptions = newSpecificDiagnosticOptions; - - foreach (var item in _diagnosticItems) - { - var effectiveSeverity = item.Descriptor.GetEffectiveSeverity(project.CompilationOptions); - item.UpdateEffectiveSeverity(effectiveSeverity); - } + var effectiveSeverity = item.Descriptor.GetEffectiveSeverity(project.CompilationOptions, newAnalyzerConfigSpecificDiagnosticOptions); + item.UpdateEffectiveSeverity(effectiveSeverity); } } } } - } } diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs index af4972b028bbb7d9178018cd12f5bea69cb9619d..bb579cbd84db4da8df1888d8f0bf17f9db3f9407 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs @@ -11,8 +11,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer { - using Workspace = Microsoft.CodeAnalysis.Workspace; - internal partial class CpsDiagnosticItemSource : BaseDiagnosticItemSource, INotifyPropertyChanged { private readonly IVsHierarchyItem _item; @@ -28,18 +26,16 @@ public CpsDiagnosticItemSource(Workspace workspace, string projectPath, ProjectI _item = item; _projectDirectoryPath = Path.GetDirectoryName(projectPath); - _analyzerReference = TryGetAnalyzerReference(_workspace.CurrentSolution); + _analyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution); if (_analyzerReference == null) { // The workspace doesn't know about the project and/or the analyzer yet. // Hook up an event handler so we can update when it does. - _workspace.WorkspaceChanged += OnWorkspaceChangedLookForAnalyzer; + Workspace.WorkspaceChanged += OnWorkspaceChangedLookForAnalyzer; } } - public IContextMenuController DiagnosticItemContextMenuController => _commandHandler.DiagnosticContextMenuController; - public Workspace Workspace => _workspace; - public ProjectId ProjectId => _projectId; + public IContextMenuController DiagnosticItemContextMenuController => CommandHandler.DiagnosticContextMenuController; public override object SourceItem => _item; @@ -55,23 +51,23 @@ private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEve e.Kind == WorkspaceChangeKind.SolutionReloaded || e.Kind == WorkspaceChangeKind.SolutionRemoved) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; } else if (e.Kind == WorkspaceChangeKind.SolutionAdded) { _analyzerReference = TryGetAnalyzerReference(e.NewSolution); if (_analyzerReference != null) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } } - else if (e.ProjectId == _projectId) + else if (e.ProjectId == ProjectId) { if (e.Kind == WorkspaceChangeKind.ProjectRemoved) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; } else if (e.Kind == WorkspaceChangeKind.ProjectAdded || e.Kind == WorkspaceChangeKind.ProjectChanged) @@ -79,7 +75,7 @@ private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEve _analyzerReference = TryGetAnalyzerReference(e.NewSolution); if (_analyzerReference != null) { - _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } @@ -89,7 +85,7 @@ private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEve private AnalyzerReference TryGetAnalyzerReference(Solution solution) { - var project = solution.GetProject(_projectId); + var project = solution.GetProject(ProjectId); if (project == null) { diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs index 734352af0a1fe897a1dc868918f7b330e0e17651..1506cc5f423601c2656e91e5e006b31605efa2f8 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs @@ -30,7 +30,7 @@ public override AnalyzerReference AnalyzerReference protected override BaseDiagnosticItem CreateItem(DiagnosticDescriptor diagnostic, ReportDiagnostic effectiveSeverity) { - return new LegacyDiagnosticItem(_item, diagnostic, effectiveSeverity, _commandHandler.DiagnosticContextMenuController); + return new LegacyDiagnosticItem(_item, diagnostic, effectiveSeverity, CommandHandler.DiagnosticContextMenuController); } } } diff --git a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.Designer.cs b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.Designer.cs index 835cf42eeaae4d80e3ce264595839b46c8ccddce..8861f0dffde59d6e5d5895e22fc9578eb5f84c07 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.Designer.cs +++ b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.Designer.cs @@ -321,6 +321,15 @@ internal class SolutionExplorerShim { } } + /// + /// Looks up a localized string similar to Updating severity. + /// + internal static string Updating_severity { + get { + return ResourceManager.GetString("Updating_severity", resourceCulture); + } + } + /// /// Looks up a localized string similar to Warning. /// diff --git a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.resx b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.resx index e3bf109a5ccbaf3955b708cb56131ae4fd0c649f..58495e154590a4f3d28aeecf820683d879fa1b25 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.resx +++ b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.resx @@ -207,4 +207,7 @@ Title + + Updating severity + \ No newline at end of file diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.cs.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.cs.xlf index 7a9d6a105053cb7488df6d9f3b5b558040350313..afd0f99eb05738ccf9c314c44a51b4db37222e8a 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.cs.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.cs.xlf @@ -62,6 +62,11 @@ Chyba + + Updating severity + Updating severity + + Warning Upozornění diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.de.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.de.xlf index 6ddcf20058f32aa6b59b899b6c1ba0db0a082212..e495f46fe6845c3a08fe1e6949efb3e42227054c 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.de.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.de.xlf @@ -62,6 +62,11 @@ Fehler + + Updating severity + Updating severity + + Warning Warnung diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.es.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.es.xlf index e92107db189225b3e5da7e3446e9dbce71de4afb..70f108ac7d1564da8ab27ef2ae484e13251ee1f9 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.es.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.es.xlf @@ -62,6 +62,11 @@ Fehler + + Updating severity + Updating severity + + Warning Advertencia diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.fr.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.fr.xlf index 4d78351094fcdb4f2c314f17e9ca020c66f20e7f..856b41270021874c56729ab4665ec3d241bb2c03 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.fr.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.fr.xlf @@ -62,6 +62,11 @@ Erreur + + Updating severity + Updating severity + + Warning Avertissement diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.it.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.it.xlf index 99ddd453c67d8c0a253da7ec6d75386b77adbe3b..a01df421268dc59303fd61c150f2e68f63b7fc28 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.it.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.it.xlf @@ -62,6 +62,11 @@ Errore + + Updating severity + Updating severity + + Warning Avviso diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ja.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ja.xlf index 617679a28997342c4806541ff5fd80bc0fc84510..9cc55c57ad13f6483325a052aaa236a899c98a12 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ja.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ja.xlf @@ -62,6 +62,11 @@ エラー + + Updating severity + Updating severity + + Warning 警告 diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ko.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ko.xlf index 7dd13048ccc2b3ee30c5bbb2982c2c3b1c89dd0e..bfcc8dfacea9aeccba4984aad3819c6e8dca7639 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ko.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ko.xlf @@ -62,6 +62,11 @@ 오류 + + Updating severity + Updating severity + + Warning 경고 diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pl.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pl.xlf index 47b7f23de764866bd0c3bf80ccc873f711beb6ee..b764f37902b6610a1b59bfac1a5a02425f5e76ba 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pl.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pl.xlf @@ -62,6 +62,11 @@ Błąd + + Updating severity + Updating severity + + Warning Ostrzeżenie diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pt-BR.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pt-BR.xlf index 60a47309008c3f5eb0247157fa63965c84947bd4..7bb2eaee147a7a2a3e157f08d8a8f11aa3368c54 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pt-BR.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.pt-BR.xlf @@ -62,6 +62,11 @@ Erro + + Updating severity + Updating severity + + Warning Aviso diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ru.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ru.xlf index 244c5259d2a4fd06541ed5fcab9a1fefcfc2f624..f0876316f9cc0e409bcc27d707e173fd1fee66cf 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ru.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.ru.xlf @@ -62,6 +62,11 @@ Ошибка + + Updating severity + Updating severity + + Warning Предупреждение diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.tr.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.tr.xlf index f1a3e9e7a7dd8e306c583d17188be3b4dde93825..1254939186f3d90b210199fb5fd2b5d206343632 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.tr.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.tr.xlf @@ -62,6 +62,11 @@ Hata + + Updating severity + Updating severity + + Warning Uyarı diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hans.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hans.xlf index 4364de4d50cba0083926244593694ca96f4dc677..f6ad98e7ce6c5c9af76f6cd4e9eedd04a91f3fb7 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hans.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hans.xlf @@ -62,6 +62,11 @@ 错误 + + Updating severity + Updating severity + + Warning 警告 diff --git a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hant.xlf b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hant.xlf index 8a346b20c91561956b9ba494975b7b3e870fbcb2..7ceb14f3f14df88b26dc07e43ddccfb79107b894 100644 --- a/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hant.xlf +++ b/src/VisualStudio/Core/SolutionExplorerShim/xlf/SolutionExplorerShim.zh-Hant.xlf @@ -62,6 +62,11 @@ 錯誤 + + Updating severity + Updating severity + + Warning 警告 diff --git a/src/Workspaces/Core/Portable/Extensions/NotificationOptionExtensions.cs b/src/Workspaces/Core/Portable/Extensions/NotificationOptionExtensions.cs index 4cee2a2846629f6cfb8bbdd8b74e416c2f8a6513..bef1619b27787d1eaacab8a105d3e839da81034f 100644 --- a/src/Workspaces/Core/Portable/Extensions/NotificationOptionExtensions.cs +++ b/src/Workspaces/Core/Portable/Extensions/NotificationOptionExtensions.cs @@ -1,22 +1,10 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Roslyn.Utilities; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.CodeAnalysis.CodeStyle { internal static class NotificationOptionExtensions { public static string ToEditorConfigString(this NotificationOption notificationOption) - { - return notificationOption.Severity switch - { - ReportDiagnostic.Suppress => EditorConfigSeverityStrings.None, - ReportDiagnostic.Hidden => EditorConfigSeverityStrings.Silent, - ReportDiagnostic.Info => EditorConfigSeverityStrings.Suggestion, - ReportDiagnostic.Warn => EditorConfigSeverityStrings.Warning, - ReportDiagnostic.Error => EditorConfigSeverityStrings.Error, - _ => throw ExceptionUtilities.UnexpectedValue(notificationOption.Severity) - }; - } + => notificationOption.Severity.ToEditorConfigString(); } } diff --git a/src/Workspaces/Core/Portable/Extensions/ReportDiagnosticExtensions.cs b/src/Workspaces/Core/Portable/Extensions/ReportDiagnosticExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..92509ede62d5b4b96f39eb1d8fee56cb4e9ad30e --- /dev/null +++ b/src/Workspaces/Core/Portable/Extensions/ReportDiagnosticExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + internal static class ReportDiagnosticExtensions + { + public static string ToEditorConfigString(this ReportDiagnostic reportDiagnostic) + { + return reportDiagnostic switch + { + ReportDiagnostic.Suppress => EditorConfigSeverityStrings.None, + ReportDiagnostic.Hidden => EditorConfigSeverityStrings.Silent, + ReportDiagnostic.Info => EditorConfigSeverityStrings.Suggestion, + ReportDiagnostic.Warn => EditorConfigSeverityStrings.Warning, + ReportDiagnostic.Error => EditorConfigSeverityStrings.Error, + _ => throw ExceptionUtilities.UnexpectedValue(reportDiagnostic) + }; + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/DiagnosticDescriptorExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/DiagnosticDescriptorExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..cfebedd79cf76ed878be83bc6dbe6735e7eb5d2d --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/DiagnosticDescriptorExtensions.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + internal static class DiagnosticDescriptorExtensions + { + /// + /// Gets project-level effective severity of the given accounting for severity configurations from both the following sources: + /// 1. Compilation options from ruleset file, if any, and command line options such as /nowarn, /warnaserror, etc. + /// 2. Analyzer config documents at the project root directory or in ancestor directories. + /// + public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor descriptor, CompilationOptions compilationOptions, ImmutableDictionary analyzerConfigSpecificDiagnosticOptions) + { + var effectiveSeverity = descriptor.GetEffectiveSeverity(compilationOptions); + + // Apply analyzer config options on top of compilation options, unless the diagnostic is explicitly suppressed by compilation options (/nowarn). + var isSuppressedByCompilationOptions = effectiveSeverity == ReportDiagnostic.Suppress && + compilationOptions.SpecificDiagnosticOptions.ContainsKey(descriptor.Id); + if (!isSuppressedByCompilationOptions && + analyzerConfigSpecificDiagnosticOptions.TryGetValue(descriptor.Id, out var reportDiagnostic)) + { + effectiveSeverity = reportDiagnostic; + } + + return effectiveSeverity; + } + + /// + /// Gets project-level effective severity of the given accounting for severity configurations from both the following sources: + /// 1. Compilation options from ruleset file, if any, and command line options such as /nowarn, /warnaserror, etc. + /// 2. Analyzer config documents at the project root directory or in ancestor directories. + /// + public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor descriptor, Project project) + => descriptor.GetEffectiveSeverity(project.CompilationOptions, project.GetAnalyzerConfigSpecialDiagnosticOptions()); + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ProjectExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ProjectExtensions.cs index 7154dd7374eba863bcd01acf5b35ff75908462ba..2eec883d6c1859bcc6a074b969c297baa3f1c5c0 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ProjectExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ProjectExtensions.cs @@ -1,7 +1,12 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions { @@ -38,5 +43,80 @@ public static async Task GetVersionAsync(this Project project, Can return version.GetNewerVersion(latestVersion); } + + public static string TryGetAnalyzerConfigPathForProjectConfiguration(this Project project) + => TryGetAnalyzerConfigPathForProjectOrDiagnosticConfiguration(project, diagnosticOpt: null); + + public static string TryGetAnalyzerConfigPathForDiagnosticConfiguration(this Project project, Diagnostic diagnostic) + { + Debug.Assert(diagnostic != null); + return TryGetAnalyzerConfigPathForProjectOrDiagnosticConfiguration(project, diagnostic); + } + + private static string TryGetAnalyzerConfigPathForProjectOrDiagnosticConfiguration(Project project, Diagnostic diagnosticOpt) + { + if (project.AnalyzerConfigDocuments.Any()) + { + var diagnosticFilePath = PathUtilities.GetDirectoryName(diagnosticOpt?.Location.SourceTree?.FilePath ?? project.FilePath); + if (!PathUtilities.IsAbsolute(diagnosticFilePath)) + { + return null; + } + + // Currently, we use a simple heuristic to find existing .editorconfig file. + // We start from the directory of the source file where the diagnostic was reported and walk up + // the directory tree to find an .editorconfig file. + // In future, we might change this algorithm, or allow end users to customize it based on options. + + var bestPath = string.Empty; + AnalyzerConfigDocument bestAnalyzerConfigDocument = null; + foreach (var analyzerConfigDocument in project.AnalyzerConfigDocuments) + { + var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigDocument.FilePath); + if (diagnosticFilePath.StartsWith(analyzerConfigDirectory) && + analyzerConfigDirectory.Length > bestPath.Length) + { + bestPath = analyzerConfigDirectory; + bestAnalyzerConfigDocument = analyzerConfigDocument; + } + } + + if (bestAnalyzerConfigDocument != null) + { + return bestAnalyzerConfigDocument.FilePath; + } + } + + // Did not find any existing .editorconfig, so create one at root of the project. + if (!PathUtilities.IsAbsolute(project.FilePath)) + { + return null; + } + + var projectFilePath = PathUtilities.GetDirectoryName(project.FilePath); + return PathUtilities.CombineAbsoluteAndRelativePaths(projectFilePath, ".editorconfig"); + } + + public static AnalyzerConfigDocument TryGetExistingAnalyzerConfigDocumentAtPath(this Project project, string analyzerConfigPath) + { + Debug.Assert(analyzerConfigPath != null); + Debug.Assert(PathUtilities.IsAbsolute(analyzerConfigPath)); + + return project.AnalyzerConfigDocuments.FirstOrDefault(d => d.FilePath == analyzerConfigPath); + } + + public static AnalyzerConfigDocument GetOrCreateAnalyzerConfigDocument(this Project project, string analyzerConfigPath) + { + var existingAnalyzerConfigDocument = project.TryGetExistingAnalyzerConfigDocumentAtPath(analyzerConfigPath); + if (existingAnalyzerConfigDocument != null) + { + return existingAnalyzerConfigDocument; + } + + var id = DocumentId.CreateNewId(project.Id); + var documentInfo = DocumentInfo.Create(id, ".editorconfig", filePath: analyzerConfigPath); + var newSolution = project.Solution.AddAnalyzerConfigDocuments(ImmutableArray.Create(documentInfo)); + return newSolution.GetProject(project.Id).GetAnalyzerConfigDocument(id); + } } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs index 3349fd1512c04b7e6dac684cde5e8fdfc0b2c2c2..d56621a07b5c093ba66ec6b532e793605beb7002 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Threading; @@ -603,6 +604,9 @@ public Project RemoveAnalyzerConfigDocument(DocumentId documentId) return this.Solution.RemoveAnalyzerConfigDocument(documentId).GetProject(this.Id); } + internal ImmutableDictionary GetAnalyzerConfigSpecialDiagnosticOptions() + => _projectState.GetAnalyzerConfigSpecialDiagnosticOptions(); + private string GetDebuggerDisplay() { return this.Name; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index 4c3ffae78818d7e4eaa04a5a3648755399666455..d6b4a94173fc6f17582316257ae67b4f326c15ff 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -260,6 +260,37 @@ public AnalyzerOptions AnalyzerOptions } } + public ImmutableDictionary GetAnalyzerConfigSpecialDiagnosticOptions() + { + // We need to find the analyzer config options at the root of the project. + // Currently, there is no compiler API to query analyzer config options for a directory in a language agnostic fashion. + // So, we use a dummy language-specific file name appended to the project directory to query analyzer config options. + + var projectDirectory = PathUtilities.GetDirectoryName(_projectInfo.FilePath); + if (!PathUtilities.IsAbsolute(projectDirectory)) + { + return ImmutableDictionary.Empty; + } + + var fileName = Guid.NewGuid().ToString(); + string sourceFilePath; + switch (_projectInfo.Language) + { + case LanguageNames.CSharp: + sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.cs"); + break; + + case LanguageNames.VisualBasic: + sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.vb"); + break; + + default: + return ImmutableDictionary.Empty; + } + + return _lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(sourceFilePath).TreeOptions; + } + private sealed class WorkspaceAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider { private readonly ProjectState _projectState;