public async Task <CodeAction> IntroduceVariableAsync( Document document, TextSpan textSpan, CodeCleanupOptions options, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_IntroduceVariable, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateAsync((TService)this, semanticDocument, options, textSpan, cancellationToken).ConfigureAwait(false); if (state != null) { var(title, actions) = CreateActions(state, cancellationToken); if (actions.Length > 0) { // We may end up creating a lot of viable code actions for the selected // piece of code. Create a top level code action so that we don't overwhelm // the light bulb if there are a lot of other options in the list. Set // the code action as 'inlinable' so that if the lightbulb is not cluttered // then the nested items can just be lifted into it, giving the user fast // access to them. return(CodeActionWithNestedActions.Create(title, actions, isInlinable: true)); } } return(null); } }
protected virtual (string description, bool hasExistingImport) GetDescription( Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { return(provider.GetDescription( document, options.AddImportOptions, SymbolResult.Symbol, semanticModel, node, cancellationToken)); }
private protected static async Task AssertCodeCleanupResult(string expected, string code, CodeStyleOption2 <AddImportPlacement> preferredImportPlacement, bool systemUsingsFirst = true, bool separateUsingGroups = false) { using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); var solution = workspace.CurrentSolution .WithOptions(workspace.Options .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp, systemUsingsFirst) .WithChangedOption(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp, separateUsingGroups) .WithChangedOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, preferredImportPlacement)) .WithAnalyzerReferences(new[] { new AnalyzerFileReference(typeof(CSharpCompilerDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile), new AnalyzerFileReference(typeof(UseExpressionBodyDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile) }); workspace.TryApplyChanges(solution); // register this workspace to solution crawler so that analyzer service associate itself with given workspace var incrementalAnalyzerProvider = workspace.ExportProvider.GetExportedValue <IDiagnosticAnalyzerService>() as IIncrementalAnalyzerProvider; incrementalAnalyzerProvider.CreateIncrementalAnalyzer(workspace); var hostdoc = workspace.Documents.Single(); var document = workspace.CurrentSolution.GetDocument(hostdoc.Id); var codeCleanupService = document.GetLanguageService <ICodeCleanupService>(); var enabledDiagnostics = codeCleanupService.GetAllDiagnostics(); var fallbackOptions = new CodeActionOptions( CleanupOptions: CodeCleanupOptions.GetDefault(document.Project.LanguageServices) with { FormattingOptions = new CSharpSyntaxFormattingOptions(separateImportDirectiveGroups: separateUsingGroups) });
private async Task <ImmutableArray <TextChange> > GetTextChangesAsync( Document document, SyntaxNode contextNode, CodeCleanupOptions options, bool hasExistingImport, CancellationToken cancellationToken) { // Defer to the language to add the actual import/using. if (hasExistingImport) { return(ImmutableArray <TextChange> .Empty); } (var newContextNode, var newDocument) = await ReplaceNameNodeAsync( contextNode, document, cancellationToken).ConfigureAwait(false); var updatedDocument = await provider.AddImportAsync( newContextNode, SymbolResult.Symbol, newDocument, options.AddImportOptions, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( updatedDocument, options, cancellationToken).ConfigureAwait(false); var textChanges = await cleanedDocument.GetTextChangesAsync( document, cancellationToken).ConfigureAwait(false); return(textChanges.ToImmutableArray()); }
public async Task CodeCleanersCSharp_Document() { var document = CreateDocument("class C { }", LanguageNames.CSharp); var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.LanguageServices)); Assert.Equal(document, cleanDocument); }
public async Task CodeCleanersVisualBasic_Document() { var document = CreateDocument(@"Class C End Class", LanguageNames.VisualBasic); var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.LanguageServices)); Assert.Equal(document, cleanDocument); }
public override async Task <AddImportFixData> TryGetFixDataAsync( Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var textChanges = await GetTextChangesAsync( document, node, options, cancellationToken).ConfigureAwait(false); return(AddImportFixData.CreateForPackageSymbol( textChanges, _source, _packageName, _versionOpt)); }
public async Task CodeCleanersCSharp_Annotation() { var document = CreateDocument("class C { }", LanguageNames.CSharp); var annotation = new SyntaxAnnotation(); document = document.WithSyntaxRoot((await document.GetSyntaxRootAsync()).WithAdditionalAnnotations(annotation)); var cleanDocument = await CodeCleaner.CleanupAsync(document, annotation, CodeCleanupOptions.GetDefault(document.Project.LanguageServices)); Assert.Equal(document, cleanDocument); }
internal IntroduceVariableAllOccurrenceCodeAction( TService service, SemanticDocument document, CodeCleanupOptions options, TExpressionSyntax expression, bool allOccurrences, bool isConstant, bool isLocal, bool isQueryLocal) : base(service, document, options, expression, allOccurrences, isConstant, isLocal, isQueryLocal) { }
public override async Task <AddImportFixData> TryGetFixDataAsync( Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var textChanges = await GetTextChangesAsync(document, node, options, cancellationToken).ConfigureAwait(false); var title = $"{provider.GetDescription(SearchResult.NameParts)} ({string.Format(FeaturesResources.from_0, _referenceAssemblyWithType.AssemblyName)})"; var fullyQualifiedTypeName = string.Join( ".", _referenceAssemblyWithType.ContainingNamespaceNames.Concat(_referenceAssemblyWithType.TypeName)); return(AddImportFixData.CreateForReferenceAssemblySymbol( textChanges, title, _referenceAssemblyWithType.AssemblyName, fullyQualifiedTypeName)); }
protected override (string description, bool hasExistingImport) GetDescription( Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var(description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return(null, false); } return(string.Format(FeaturesResources.Add_reference_to_0, Path.GetFileName(_reference.FilePath)), hasExistingImport); }
public static async Task <State> GenerateAsync( TService service, SemanticDocument document, CodeCleanupOptions options, TextSpan textSpan, CancellationToken cancellationToken) { var state = new State(service, document, options); if (!await state.TryInitializeAsync(document, textSpan, cancellationToken).ConfigureAwait(false)) { return(null); } return(state); }
protected static async Task <SyntaxNode> ExtractMethodAsync( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool dontPutOutOrRefOnStruct = true, bool allowBestEffort = false) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = new ExtractMethodGenerationOptions( ExtractOptions: new ExtractMethodOptions(dontPutOutOrRefOnStruct), CodeGenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), AddImportOptions: AddImportPlacementOptions.Default, NamingPreferences: _ => NamingStylePreferences.Default); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options.ExtractOptions, localFunction: false); var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None); if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) { return(null); } Assert.True(selectedCode.ContainsValidContext); // extract method var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, options, localFunction: false); var result = await extractor.ExtractMethodAsync(CancellationToken.None); Assert.NotNull(result); Assert.Equal(succeed, result.Succeeded || result.SucceededWithSuggestion || (allowBestEffort && result.Status.HasBestEffort())); var(doc, _) = await result.GetFormattedDocumentAsync(CodeCleanupOptions.GetDefault(document.Project.LanguageServices), CancellationToken.None); return(doc == null ? null : await doc.GetSyntaxRootAsync()); }
internal static async Task <Document> CleanupDocumentAsync( Document document, CodeCleanupOptions options, CancellationToken cancellationToken) { document = await ImportAdder.AddImportsFromSymbolAnnotationAsync( document, Simplifier.AddImportsAnnotation, options.AddImportOptions, cancellationToken).ConfigureAwait(false); document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, options.SimplifierOptions, cancellationToken).ConfigureAwait(false); // format any node with explicit formatter annotation document = await Formatter.FormatAsync(document, Formatter.Annotation, options.FormattingOptions, cancellationToken).ConfigureAwait(false); // format any elastic whitespace document = await Formatter.FormatAsync(document, SyntaxAnnotation.ElasticAnnotation, options.FormattingOptions, cancellationToken).ConfigureAwait(false); document = await CaseCorrector.CaseCorrectAsync(document, CaseCorrector.Annotation, cancellationToken).ConfigureAwait(false); return(document); }
protected override (string description, bool hasExistingImport) GetDescription( Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var(description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return(null, false); } var project = document.Project; description = project.Id == _project.Id ? description : string.Format(FeaturesResources.Add_reference_to_0, _project.Name); return(description, hasExistingImport); }
public sealed override async Task <AddImportFixData> TryGetFixDataAsync( Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var(description, hasExistingImport) = GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return(null); } if (hasExistingImport && !ShouldAddWithExistingImport(document)) { return(null); } var isFuzzy = !SearchResult.DesiredNameMatchesSourceName(document); var tags = GetTags(document); if (isFuzzy) { // The name is going to change. Make it clear in the description that this is // going to happen. description = $"{SearchResult.DesiredName} - {description}"; // if we were a fuzzy match, and we didn't have any glyph to show, then add the // namespace-glyph to this item. This helps indicate that not only are we fixing // the spelling of this name we are *also* adding a namespace. This helps as we // have gotten feedback in the past that the 'using/import' addition was // unexpected. if (tags.IsDefaultOrEmpty) { tags = WellKnownTagArrays.Namespace; } } var textChanges = await GetTextChangesAsync( document, node, options, hasExistingImport, cancellationToken).ConfigureAwait(false); return(GetFixData( document, textChanges, description, tags, GetPriority(document))); }
public static async ValueTask <OmniSharpSyntaxFormattingOptionsWrapper> FromDocumentAsync(Document document, OmniSharpLineFormattingOptions fallbackLineFormattingOptions, CancellationToken cancellationToken) { var defaultOptions = CodeCleanupOptions.GetDefault(document.Project.LanguageServices); var fallbackOptions = defaultOptions with { FormattingOptions = defaultOptions.FormattingOptions.With(new LineFormattingOptions { IndentationSize = fallbackLineFormattingOptions.IndentationSize, TabSize = fallbackLineFormattingOptions.TabSize, UseTabs = fallbackLineFormattingOptions.UseTabs, NewLine = fallbackLineFormattingOptions.NewLine, }) }; var cleanupOptions = await document.GetCodeCleanupOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); return(new OmniSharpSyntaxFormattingOptionsWrapper(cleanupOptions)); } }
public override ValueTask <CleanCodeGenerationOptions> GetCleanCodeGenerationOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) { var lineFormattingOptions = _lineFormattingOptionsProvider.GetLineFormattingOptions(); var codeGenerationOptions = CleanCodeGenerationOptions.GetDefault(languageServices) with { CleanupOptions = CodeCleanupOptions.GetDefault(languageServices) with { FormattingOptions = SyntaxFormattingOptions.GetDefault(languageServices).With(new LineFormattingOptions { IndentationSize = lineFormattingOptions.IndentationSize, TabSize = lineFormattingOptions.TabSize, UseTabs = lineFormattingOptions.UseTabs, NewLine = lineFormattingOptions.NewLine, }) } }; return(new ValueTask <CleanCodeGenerationOptions>(codeGenerationOptions)); }
protected async Task <ImmutableArray <TextChange> > GetTextChangesAsync( Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var originalDocument = document; (node, document) = await ReplaceNameNodeAsync( node, document, cancellationToken).ConfigureAwait(false); var newDocument = await provider.AddImportAsync( node, SearchResult.NameParts, document, options.AddImportOptions, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( newDocument, options, cancellationToken).ConfigureAwait(false); var textChanges = await cleanedDocument.GetTextChangesAsync( originalDocument, cancellationToken).ConfigureAwait(false); return(textChanges.ToImmutableArray()); }
private static async Task <ImmutableArray <CodeAction> > GetCodeActionsAsync( Document document, TextSpan textSpan, ExtractMethodGenerationOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { using var _ = ArrayBuilder <CodeAction> .GetInstance(out var actions); var methodAction = await ExtractMethodAsync(document, textSpan, extractOptions, cleanupOptions, cancellationToken).ConfigureAwait(false); actions.AddIfNotNull(methodAction); var localFunctionAction = await ExtractLocalFunctionAsync(document, textSpan, extractOptions, cleanupOptions, cancellationToken).ConfigureAwait(false); actions.AddIfNotNull(localFunctionAction); return(actions.ToImmutable()); }
public async Task DontCrash_VB_2() { var code = @" Public Class Class1 Public Custom Event Event2 As EventHandler AddHandler(ByVal value As EventHandler) End AddHandler RemoveHandler(ByVal value As EventHandler) End RemoveHandler RaiseEvent(ByVal sender As Object, ByVal e As EventArgs) e End Event End Class "; var document = CreateDocument(code, LanguageNames.VisualBasic); var semanticModel = await document.GetSemanticModelAsync(); var root = await document.GetSyntaxRootAsync(); var accessor = root.DescendantNodes().OfType <VisualBasic.Syntax.AccessorBlockSyntax>().Last(); var newSemanticModel = await document.ReuseExistingSpeculativeModelAsync(accessor.Statements[0], CancellationToken.None); Assert.NotNull(newSemanticModel); Assert.False(newSemanticModel.IsSpeculativeSemanticModel); var newDocument = CreateDocument(code, LanguageNames.VisualBasic); var newRoot = await newDocument.GetSyntaxRootAsync(); var newAccessor = newRoot.DescendantNodes().OfType <VisualBasic.Syntax.AccessorBlockSyntax>().Last(); root = root.ReplaceNode(accessor, newAccessor); document = document.WithSyntaxRoot(root); accessor = root.DescendantNodes().OfType <VisualBasic.Syntax.AccessorBlockSyntax>().Last(); newSemanticModel = await document.ReuseExistingSpeculativeModelAsync(accessor.Statements[0], CancellationToken.None); Assert.NotNull(newSemanticModel); Assert.True(newSemanticModel.IsSpeculativeSemanticModel); var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.LanguageServices)); Assert.Equal(document, cleanDocument); }
internal AbstractIntroduceVariableCodeAction( TService service, SemanticDocument document, CodeCleanupOptions options, TExpressionSyntax expression, bool allOccurrences, bool isConstant, bool isLocal, bool isQueryLocal) { _service = service; _semanticDocument = document; Options = options; _expression = expression; _allOccurrences = allOccurrences; _isConstant = isConstant; _isLocal = isLocal; _isQueryLocal = isQueryLocal; Title = CreateDisplayText(expression); }
internal async Task TestAsync(string testCode, string expected, OptionsCollection?options = null, ParseOptions?parseOptions = null) { using var workspace = CreateTestWorkspace(testCode, parseOptions); options?.SetGlobalOptions(workspace.GlobalOptions); var solution = workspace.CurrentSolution; var document = workspace.CurrentSolution.Projects.First().Documents.First(); var languageServices = document.Project.LanguageServices; var cleanupOptions = options?.ToAnalyzerConfigOptions(languageServices).GetCodeCleanupOptions(allowImportsInHiddenRegions: false, fallbackOptions: null, languageServices) ?? CodeCleanupOptions.GetDefault(languageServices); var formattingService = document.GetRequiredLanguageService <INewDocumentFormattingService>(); var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument : null, cleanupOptions, CancellationToken.None); var actual = await formattedDocument.GetTextAsync(); AssertEx.EqualOrDiff(expected, actual.ToString()); }
public void OptionsAreMessagePackSerializable(string language) { var messagePackOptions = MessagePackSerializerOptions.Standard.WithResolver(MessagePackFormatters.DefaultResolver); using var workspace = new AdhocWorkspace(); var languageServices = workspace.Services.GetLanguageServices(language); var options = new object[] { SimplifierOptions.GetDefault(languageServices), SyntaxFormattingOptions.GetDefault(languageServices), CodeCleanupOptions.GetDefault(languageServices), CodeGenerationOptions.GetDefault(languageServices), IdeCodeStyleOptions.GetDefault(languageServices), CodeActionOptions.GetDefault(languageServices), IndentationOptions.GetDefault(languageServices), ExtractMethodGenerationOptions.GetDefault(languageServices), // some non-default values: new VisualBasicIdeCodeStyleOptions( new IdeCodeStyleOptions.CommonOptions() { AllowStatementImmediatelyAfterBlock = new CodeStyleOption2 <bool>(false, NotificationOption2.Error) }, PreferredModifierOrder: new CodeStyleOption2 <string>("Public Private", NotificationOption2.Error)) }; foreach (var original in options) { using var stream = new MemoryStream(); MessagePackSerializer.Serialize(stream, original, messagePackOptions); stream.Position = 0; var deserialized = MessagePackSerializer.Deserialize(original.GetType(), stream, messagePackOptions); Assert.Equal(original, deserialized); } }
private static void VerifyRange(string code, ImmutableArray <ICodeCleanupProvider> codeCleanups, ImmutableArray <TextSpan> spans, ref IEnumerable <TextSpan> expectedResult, string language) { var result = (IEnumerable <TextSpan>)null; var spanCodeCleanup = new MockCodeCleanupProvider() { CleanupDocumentAsyncImpl = (document, spans, options, cancellationToken) => { result = spans; return(Task.FromResult(document)); } }; var document = CreateDocument(code, language); CodeCleaner.CleanupAsync(document, spans, CodeCleanupOptions.GetDefault(document.Project.LanguageServices), codeCleanups.Concat(spanCodeCleanup)).Wait(); var sortedSpans = result.ToList(); var expectedSpans = expectedResult.ToList(); sortedSpans.Sort(); expectedSpans.Sort(); AssertEx.Equal(expectedSpans, sortedSpans); }
public async Task <Document> FormatNewDocumentAsync(Document document, Document?hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = (CompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var namespaces = GetNamespacesToReplace(document, root, optionSet).ToList(); if (namespaces.Count != 1) { return(document); } return(await ConvertNamespaceTransform.ConvertAsync(document, namespaces[0], options.FormattingOptions, cancellationToken).ConfigureAwait(false)); }
public async Task <Document> FormatNewDocumentAsync(Document document, Document?hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var rootToFormat = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Apply file header preferences var fileHeaderTemplate = options.DocumentFormattingOptions.FileHeaderTemplate; if (!string.IsNullOrEmpty(fileHeaderTemplate)) { var newLineTrivia = SyntaxGeneratorInternal.EndOfLine(options.FormattingOptions.NewLine); var rootWithFileHeader = await AbstractFileHeaderCodeFixProvider.GetTransformedSyntaxRootAsync( SyntaxGenerator.SyntaxFacts, FileHeaderHelper, newLineTrivia, document, fileHeaderTemplate, cancellationToken).ConfigureAwait(false); return(document.WithSyntaxRoot(rootWithFileHeader)); } else if (hintDocument is not null) { // If there is no file header preference, see if we can use the one in the hint document var bannerService = hintDocument.GetRequiredLanguageService <IFileBannerFactsService>(); var hintSyntaxRoot = await hintDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var fileBanner = bannerService.GetFileBanner(hintSyntaxRoot); var rootWithBanner = rootToFormat.WithPrependedLeadingTrivia(fileBanner); return(document.WithSyntaxRoot(rootWithBanner)); } return(document); }
private static async Task <CodeAction> ExtractMethodAsync(Document document, TextSpan textSpan, ExtractMethodGenerationOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { var result = await ExtractMethodService.ExtractMethodAsync( document, textSpan, localFunction : false, extractOptions, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(result); if (!result.Succeeded && !result.SucceededWithSuggestion) { return(null); } return(CodeAction.Create( FeaturesResources.Extract_method, async c => { var(document, invocationNameToken) = await result.GetFormattedDocumentAsync(cleanupOptions, c).ConfigureAwait(false); return await AddRenameAnnotationAsync(document, invocationNameToken, c).ConfigureAwait(false); }, nameof(FeaturesResources.Extract_method))); }
public async Task <(Document document, SyntaxToken invocationNameToken)> GetFormattedDocumentAsync(CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { if (DocumentWithoutFinalFormatting is null) { throw new InvalidOperationException(); } var annotation = new SyntaxAnnotation(); var root = await DocumentWithoutFinalFormatting.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); root = root.ReplaceToken(InvocationNameToken, InvocationNameToken.WithAdditionalAnnotations(annotation)); var annotatedDocument = DocumentWithoutFinalFormatting.WithSyntaxRoot(root); var simplifiedDocument = await Simplifier.ReduceAsync(annotatedDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); var simplifiedRoot = await simplifiedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var services = DocumentWithoutFinalFormatting.Project.Solution.Services; var formattedDocument = simplifiedDocument.WithSyntaxRoot( Formatter.Format(simplifiedRoot, Formatter.Annotation, services, cleanupOptions.FormattingOptions, FormattingRules, cancellationToken)); var formattedRoot = await formattedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return(formattedDocument, formattedRoot.GetAnnotatedTokens(annotation).Single()); }
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 <IAddAccessibilityModifiersService>(); foreach (var declaration in typeDeclarations) { if (!service.ShouldUpdateAccessibilityModifier(CSharpAccessibilityFacts.Instance, declaration, accessibilityPreferences, 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.IsPartial) { continue; } var type = semanticModel.GetDeclaredSymbol(declaration, cancellationToken); if (type == null) { continue; } AddAccessibilityModifiersHelpers.UpdateDeclaration(editor, type, declaration); } return(document.WithSyntaxRoot(editor.GetChangedRoot())); }