| File: Formatting\CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.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. using System; using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddOrRemoveAccessibilityModifiers; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Formatting; [ExportNewDocumentFormattingProvider(LanguageNames.CSharp), Shared] internal sealed class CSharpAccessibilityModifiersNewDocumentFormattingProvider : INewDocumentFormattingProvider { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpAccessibilityModifiersNewDocumentFormattingProvider() { } public async Task<Document> FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var accessibilityPreferences = options.FormattingOptions.AccessibilityModifiersRequired; if (accessibilityPreferences == AccessibilityModifiersRequired.Never) { return document; } var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>(); var typeDeclarations = root.DescendantNodes().Where(node => syntaxFacts.IsTypeDeclaration(node)); var editor = new SyntaxEditor(root, document.Project.Solution.Services); var service = document.GetRequiredLanguageService<IAddOrRemoveAccessibilityModifiersService>(); foreach (var declaration in typeDeclarations) { if (!service.ShouldUpdateAccessibilityModifier(CSharpAccessibilityFacts.Instance, declaration, accessibilityPreferences, out _, out _)) continue; // Since we format each document as they are added to a project we can't assume we know about all // of the files that are coming, so we have to opt out of changing partial classes. This especially // manifests when creating new projects as we format before we have a project at all, so we could get a // situation like this: // // File1.cs: // partial class C { } // File2.cs: // public partial class C { } // // When we see File1, we don't know about File2, so would add an internal modifier, which would result in a compile // error. var modifiers = syntaxFacts.GetModifiers(declaration); CSharpAccessibilityFacts.GetAccessibilityAndModifiers(modifiers, out _, out var declarationModifiers, out _); if (declarationModifiers.HasFlag(Modifiers.Partial)) continue; var type = semanticModel.GetDeclaredSymbol(declaration, cancellationToken); if (type == null) continue; AddOrRemoveAccessibilityModifiersHelpers.UpdateDeclaration(editor, type, declaration); } return document.WithSyntaxRoot(editor.GetChangedRoot()); } }