private void AnalyzeNode(SyntaxNodeAnalysisContext context) { if (!AreObjectInitializersSupported(context)) { return; } var syntaxTree = context.Node.SyntaxTree; var cancellationToken = context.CancellationToken; var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult(); if (optionSet == null) { return; } var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; var option = optionSet.GetOption(CodeStyleOptions.PreferObjectInitializer, language); if (!option.Value) { // not point in analyzing if the option is off. return; } var syntaxFacts = GetSyntaxFactsService(); var matches = ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclarationSyntax> .Analyze( context.SemanticModel, syntaxFacts, objectCreationExpression, context.CancellationToken); if (matches == null || matches.Value.Length == 0) { return; } var containingStatement = objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); var nodes = ImmutableArray.Create <SyntaxNode>(containingStatement).AddRange(matches.Value.Select(m => m.Statement)); if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken)) { return; } var locations = ImmutableArray.Create(objectCreationExpression.GetLocation()); var severity = option.Notification.Severity; context.ReportDiagnostic(DiagnosticHelper.Create( Descriptor, objectCreationExpression.GetLocation(), severity, additionalLocations: locations, properties: null)); FadeOutCode(context, optionSet, matches.Value, locations); }
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { // Fix-All for this feature is somewhat complicated. As Object-Initializers // could be arbitrarily nested, we have to make sure that any edits we make // to one Object-Initializer are seen by any higher ones. In order to do this // we actually process each object-creation-node, one at a time, rewriting // the tree for each node. In order to do this effectively, we use the '.TrackNodes' // feature to keep track of all the object creation nodes as we make edits to // the tree. If we didn't do this, then we wouldn't be able to find the // second object-creation-node after we make the edit for the first one. var workspace = document.Project.Solution.Workspace; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var originalRoot = editor.OriginalRoot; var originalObjectCreationNodes = new Stack <TObjectCreationExpressionSyntax>(); foreach (var diagnostic in diagnostics) { var objectCreation = (TObjectCreationExpressionSyntax)originalRoot.FindNode( diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); originalObjectCreationNodes.Push(objectCreation); } // We're going to be continually editing this tree. Track all the nodes we // care about so we can find them across each edit. document = document.WithSyntaxRoot(originalRoot.TrackNodes(originalObjectCreationNodes)); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); while (originalObjectCreationNodes.Count > 0) { var originalObjectCreation = originalObjectCreationNodes.Pop(); var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single(); var matches = ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclarationSyntax> .Analyze( semanticModel, syntaxFacts, objectCreation, cancellationToken); if (matches == null || matches.Value.Length == 0) { continue; } var statement = objectCreation.FirstAncestorOrSelf <TStatementSyntax>(); var newStatement = GetNewStatement(statement, objectCreation, matches.Value) .WithAdditionalAnnotations(Formatter.Annotation); var subEditor = new SyntaxEditor(currentRoot, workspace); subEditor.ReplaceNode(statement, newStatement); foreach (var match in matches) { subEditor.RemoveNode(match.Statement, SyntaxRemoveOptions.KeepUnbalancedDirectives); } document = document.WithSyntaxRoot(subEditor.GetChangedRoot()); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); } editor.ReplaceNode(editor.OriginalRoot, currentRoot); }