private void AnalyzeNode(SyntaxNodeAnalysisContext context) { var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; var option = context.GetAnalyzerOptions().PreferObjectInitializer; if (!option.Value) { // not point in analyzing if the option is off. return; } var syntaxFacts = GetSyntaxFacts(); var matches = UseNamedMemberInitializerAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax> .Analyze( context.SemanticModel, syntaxFacts, objectCreationExpression, context.CancellationToken); if (matches == null || matches.Value.Length == 0) { return; } var containingStatement = objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); if (containingStatement == null) { return; } if (!IsValidContainingStatement(containingStatement)) { return; } var nodes = ImmutableArray.Create <SyntaxNode>(containingStatement).AddRange(matches.Value.Select(m => m.Statement)); if (syntaxFacts.ContainsInterleavedDirective(nodes, context.CancellationToken)) { return; } var locations = ImmutableArray.Create(objectCreationExpression.GetLocation()); context.ReportDiagnostic(DiagnosticHelper.Create( Descriptor, objectCreationExpression.GetFirstToken().GetLocation(), option.Notification.Severity, locations, properties: null)); FadeOutCode(context, matches.Value, locations); }
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, 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 services = document.Project.Solution.Workspace.Services; 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.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); while (originalObjectCreationNodes.Count > 0) { var originalObjectCreation = originalObjectCreationNodes.Pop(); var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single(); var matches = UseNamedMemberInitializerAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax> .Analyze( semanticModel, syntaxFacts, objectCreation, cancellationToken); if (matches == null || matches.Value.Length == 0) { continue; } var statement = objectCreation.FirstAncestorOrSelf <TStatementSyntax>(); Contract.ThrowIfNull(statement); var newStatement = GetNewStatement(statement, objectCreation, matches.Value) .WithAdditionalAnnotations(Formatter.Annotation); var subEditor = new SyntaxEditor(currentRoot, services); 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.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); } editor.ReplaceNode(editor.OriginalRoot, currentRoot); }