private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ienumerableType) { var semanticModel = context.SemanticModel; var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; var cancellationToken = context.CancellationToken; var option = context.GetOption(CodeStyleOptions2.PreferCollectionInitializer, language); if (!option.Value) { // not point in analyzing if the option is off. return; } // Object creation can only be converted to collection initializer if it // implements the IEnumerable type. var objectType = context.SemanticModel.GetTypeInfo(objectCreationExpression, cancellationToken); if (objectType.Type == null || !objectType.Type.AllInterfaces.Contains(ienumerableType)) { return; } var matches = ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax> .Analyze( semanticModel, GetSyntaxFacts(), objectCreationExpression, cancellationToken); if (matches == null || matches.Value.Length == 0) { return; } var containingStatement = objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); if (containingStatement == null) { return; } var nodes = ImmutableArray.Create <SyntaxNode>(containingStatement).AddRange(matches.Value); var syntaxFacts = GetSyntaxFacts(); 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, matches.Value, locations); }
protected override Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { // Fix-All for this feature is somewhat complicated. As Collection-Initializers // could be arbitrarily nested, we have to make sure that any edits we make // to one Collection-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. var currentRoot = originalRoot.TrackNodes(originalObjectCreationNodes); while (originalObjectCreationNodes.Count > 0) { var originalObjectCreation = originalObjectCreationNodes.Pop(); var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single(); var analyzer = new ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>( syntaxFacts, objectCreation); var matches = analyzer.Analyze(); 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); } currentRoot = subEditor.GetChangedRoot(); } editor.ReplaceNode(originalRoot, currentRoot); return(SpecializedTasks.EmptyTask); }
private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ienumerableType) { if (!AreCollectionInitializersSupported(context)) { return; } var semanticModel = context.SemanticModel; var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; var syntaxTree = objectCreationExpression.SyntaxTree; var cancellationToken = context.CancellationToken; var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult(); if (optionSet == null) { return; } var option = optionSet.GetOption(CodeStyleOptions.PreferCollectionInitializer, language); if (!option.Value) { // not point in analyzing if the option is off. return; } // Object creation can only be converted to collection initializer if it // implements the IEnumerable type. var objectType = context.SemanticModel.GetTypeInfo(objectCreationExpression, cancellationToken); if (objectType.Type == null || !objectType.Type.AllInterfaces.Contains(ienumerableType)) { return; } var analyzer = new ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>( semanticModel, GetSyntaxFactsService(), objectCreationExpression, cancellationToken); var matches = analyzer.Analyze(); if (matches == null || matches.Value.Length == 0) { return; } var locations = ImmutableArray.Create(objectCreationExpression.GetLocation()); var severity = option.Notification.Value; context.ReportDiagnostic(Diagnostic.Create( CreateDescriptorWithSeverity(severity), objectCreationExpression.GetLocation(), additionalLocations: locations)); FadeOutCode(context, optionSet, matches.Value, locations); }