| File: Analyzers\Extensions.cs | Web Access |
| Project: src\sdk\src\Dotnet.Format\dotnet-format\dotnet-format.csproj (dotnet-format) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Collections.Immutable; using System.Reflection; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Tools.Analyzers { public static class Extensions { private static Assembly MicrosoftCodeAnalysisFeaturesAssembly { get; } private static Type IDEDiagnosticIdToOptionMappingHelperType { get; } private static MethodInfo TryGetMappedOptionsMethod { get; } static Extensions() { MicrosoftCodeAnalysisFeaturesAssembly = Assembly.Load(new AssemblyName("Microsoft.CodeAnalysis.Features")); IDEDiagnosticIdToOptionMappingHelperType = MicrosoftCodeAnalysisFeaturesAssembly.GetType("Microsoft.CodeAnalysis.Diagnostics.IDEDiagnosticIdToOptionMappingHelper")!; TryGetMappedOptionsMethod = IDEDiagnosticIdToOptionMappingHelperType.GetMethod("TryGetMappedOptions", BindingFlags.Static | BindingFlags.Public)!; } public static bool Any(this SolutionChanges solutionChanges) => solutionChanges.GetProjectChanges() .Any(x => x.GetChangedDocuments().Any() || x.GetChangedAdditionalDocuments().Any()); /// <summary> /// Get the highest possible severity for any formattable document in the project. /// </summary> public static async Task<DiagnosticSeverity> GetSeverityAsync( this DiagnosticAnalyzer analyzer, Project project, ImmutableHashSet<string> formattablePaths, CancellationToken cancellationToken) { var severity = DiagnosticSeverity.Hidden; var compilation = await project.GetCompilationAsync(cancellationToken); if (compilation is null) { return severity; } foreach (var document in project.Documents) { // Is the document formattable? if (document.FilePath is null || !formattablePaths.Contains(document.FilePath)) { continue; } var options = await document.GetOptionsAsync(cancellationToken); var documentSeverity = analyzer.GetSeverity(document, project.AnalyzerOptions, options, compilation); if (documentSeverity > severity) { severity = documentSeverity; } } return severity; } public static DiagnosticSeverity ToSeverity(this ReportDiagnostic reportDiagnostic) { return reportDiagnostic switch { ReportDiagnostic.Error => DiagnosticSeverity.Error, ReportDiagnostic.Warn => DiagnosticSeverity.Warning, ReportDiagnostic.Info => DiagnosticSeverity.Info, _ => DiagnosticSeverity.Hidden }; } private static DiagnosticSeverity GetSeverity( this DiagnosticAnalyzer analyzer, Document document, AnalyzerOptions? analyzerOptions, OptionSet options, Compilation compilation) { var severity = DiagnosticSeverity.Hidden; if (!document.TryGetSyntaxTree(out var tree)) { return severity; } foreach (var descriptor in analyzer.SupportedDiagnostics) { if (severity == DiagnosticSeverity.Error) { break; } if (analyzerOptions.TryGetSeverityFromConfiguration(tree, compilation, descriptor, out var reportDiagnostic)) { var configuredSeverity = reportDiagnostic.ToSeverity(); if (configuredSeverity > severity) { severity = configuredSeverity; } continue; } if (TryGetSeverityFromCodeStyleOption(descriptor, compilation, options, out var codeStyleSeverity)) { if (codeStyleSeverity > severity) { severity = codeStyleSeverity; } continue; } if (descriptor.DefaultSeverity > severity) { severity = descriptor.DefaultSeverity; } } return severity; static bool TryGetSeverityFromCodeStyleOption( DiagnosticDescriptor descriptor, Compilation compilation, OptionSet options, out DiagnosticSeverity severity) { severity = DiagnosticSeverity.Hidden; var parameters = new object?[] { descriptor.Id, compilation.Language, null }; var result = (bool)(TryGetMappedOptionsMethod.Invoke(null, parameters) ?? false); if (!result) { return false; } var codeStyleOptions = (IEnumerable)parameters[2]!; foreach (var codeStyleOptionObj in codeStyleOptions) { var codeStyleOption = (IOption)codeStyleOptionObj!; var option = options.GetOption(new OptionKey(codeStyleOption, codeStyleOption.IsPerLanguage ? compilation.Language : null)); if (option is null) { continue; } var notificationProperty = option.GetType().GetProperty("Notification"); if (notificationProperty is null) { continue; } var notification = notificationProperty.GetValue(option); var reportDiagnosticValue = notification?.GetType().GetProperty("Severity")?.GetValue(notification); if (reportDiagnosticValue is null) { continue; } var codeStyleSeverity = ToSeverity((ReportDiagnostic)reportDiagnosticValue); if (codeStyleSeverity > severity) { severity = codeStyleSeverity; } } return true; } } } }