| File: CodeFixes\Suppression\AbstractSuppressionCodeFixProvider.AbstractGlobalSuppressMessageCodeAction.cs | Web Access |
| Project: src\roslyn\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; internal abstract partial class AbstractSuppressionCodeFixProvider : IConfigurationFixProvider { internal abstract class AbstractGlobalSuppressMessageCodeAction : AbstractSuppressionCodeAction { private readonly Project _project; protected AbstractGlobalSuppressMessageCodeAction(AbstractSuppressionCodeFixProvider fixer, Project project) : base(fixer, title: FeaturesResources.in_Suppression_File) { _project = project; } protected sealed override async Task<ImmutableArray<CodeActionOperation>> ComputeOperationsAsync( IProgress<CodeAnalysisProgress> progress, CancellationToken cancellationToken) { var changedSuppressionDocument = await GetChangedSuppressionDocumentAsync(cancellationToken).ConfigureAwait(false); return [ new ApplyChangesOperation(changedSuppressionDocument.Project.Solution), new OpenDocumentOperation(changedSuppressionDocument.Id, activateIfAlreadyOpen: true), new DocumentNavigationOperation(changedSuppressionDocument.Id, position: 0), ]; } protected abstract Task<Document> GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken); private string GetSuppressionsFilePath(string suppressionsFileName) { if (!string.IsNullOrEmpty(_project.FilePath)) { var fullPath = Path.GetFullPath(_project.FilePath); var directory = PathUtilities.GetDirectoryName(fullPath); if (!string.IsNullOrEmpty(directory)) { var suppressionsFilePath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(directory, suppressionsFileName); if (!string.IsNullOrEmpty(suppressionsFilePath)) { return suppressionsFilePath; } } } return suppressionsFileName; } protected async Task<Document> GetOrCreateSuppressionsDocumentAsync(CancellationToken c) { var index = 1; var suppressionsFileName = s_globalSuppressionsFileName + Fixer.DefaultFileExtension; var suppressionsFilePath = GetSuppressionsFilePath(suppressionsFileName); Document suppressionsDoc = null; while (suppressionsDoc == null) { var hasDocWithSuppressionsName = false; foreach (var document in _project.Documents) { var filePath = document.FilePath; var fullPath = !string.IsNullOrEmpty(filePath) ? Path.GetFullPath(filePath) : filePath; if (fullPath == suppressionsFilePath) { // Existing global suppressions file. See if this file only has imports and global assembly // attributes. hasDocWithSuppressionsName = true; var t = await document.GetSyntaxTreeAsync(c).ConfigureAwait(false); var r = await t.GetRootAsync(c).ConfigureAwait(false); var syntaxFacts = _project.Services.GetRequiredService<ISyntaxFactsService>(); if (r.ChildNodes().All(n => syntaxFacts.IsUsingOrExternOrImport(n) || Fixer.IsAttributeListWithAssemblyAttributes(n))) { suppressionsDoc = document; break; } } } if (suppressionsDoc == null) { if (hasDocWithSuppressionsName || File.Exists(suppressionsFilePath)) { index++; suppressionsFileName = s_globalSuppressionsFileName + index.ToString() + Fixer.DefaultFileExtension; suppressionsFilePath = GetSuppressionsFilePath(suppressionsFileName); } else { // Create an empty global suppressions file. var emptyText = SourceText.From("", Encoding.UTF8, SourceHashAlgorithms.Default); suppressionsDoc = _project.AddDocument(suppressionsFileName, emptyText, filePath: suppressionsFilePath); } } } return suppressionsDoc; } } }