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 @@
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
- &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
- &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
- &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
- &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
- &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
+ ルール セットの重要度を設定
- &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
+ 규칙 집합 심각도 설정
- &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ł
- &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
- &Info
- &Информация
+ &Suggestion
+ &Информация
- Info
- Информация
+ Suggestion
+ Информация
@@ -163,13 +163,13 @@
- &Hidden
- &Скрытый
+ &Silent
+ &Скрытый
- Hidden
- Скрытый
+ Silent
+ Скрытый
@@ -333,18 +333,18 @@
- Set Rule Set Severity
- Установить серьезность набора правил
+ Set severity
+ Установить серьезность набора правил
- &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
- &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
+ 设置规则集严重性
- &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
+ 設定規則集合嚴重性
+
+ 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;