private static async Task <SyntaxNode> ExpandUsingDirectiveAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) { var usingDirective = (UsingDirectiveSyntax)node; var newName = await Simplifier.ExpandAsync(usingDirective.Name, document, cancellationToken : cancellationToken).ConfigureAwait(false); return(usingDirective.WithName(newName)); }
protected override async Task <SemanticDocument> ExpandAsync( SelectionResult selection, CancellationToken cancellationToken ) { var lastExpression = selection .GetFirstTokenInSelection() .GetCommonRoot(selection.GetLastTokenInSelection()) .GetAncestors <ExpressionSyntax>() .LastOrDefault(); if (lastExpression == null) { return(selection.SemanticDocument); } var newExpression = await Simplifier .ExpandAsync( lastExpression, selection.SemanticDocument.Document, n => n != selection.GetContainingScope(), expandParameter : false, cancellationToken : cancellationToken ) .ConfigureAwait(false); return(await selection.SemanticDocument .WithSyntaxRootAsync( selection.SemanticDocument.Root.ReplaceNode(lastExpression, newExpression), cancellationToken ) .ConfigureAwait(false)); }
private async Task <Document> MoveDeclarationNearReferenceAsync(Document document, State state, CancellationToken cancellationToken) { var innermostStatements = state.InnermostBlock.Statements.Where(s => s != state.DeclarationStatement).ToList(); var innermostAffectedIndex = innermostStatements.IndexOf(state.FirstStatementAffectedInInnermostBlock); var crossesMeaningfulBlock = CrossesMeaningfulBlock(state); var warningAnnotation = crossesMeaningfulBlock ? WarningAnnotation.Create(CSharpFeaturesResources.Warning_colon_Declaration_changes_scope_and_may_change_meaning) : null; var canMergeDeclarationAndAssignment = await CanMergeDeclarationAndAssignmentAsync(document, state, cancellationToken).ConfigureAwait(false); if (canMergeDeclarationAndAssignment) { // Replace the first reference with a new declaration. var declarationStatement = CreateMergedDeclarationStatement(state, state.FirstStatementAffectedInInnermostBlock); declarationStatement = warningAnnotation == null ? declarationStatement : declarationStatement.WithAdditionalAnnotations(warningAnnotation); innermostStatements[innermostAffectedIndex] = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation); } else { // If we're not merging with an existing declaration, make the declaration semantically // explicit to improve the chances that it won't break code. var explicitDeclarationStatement = await Simplifier.ExpandAsync(state.DeclarationStatement, document, cancellationToken : cancellationToken).ConfigureAwait(false); // place the declaration above the first statement that references it. var declarationStatement = warningAnnotation == null ? explicitDeclarationStatement : explicitDeclarationStatement.WithAdditionalAnnotations(warningAnnotation); innermostStatements.Insert(innermostAffectedIndex, declarationStatement.WithAdditionalAnnotations(Formatter.Annotation)); } var newInnermostBlock = state.InnermostBlock.WithStatements( SyntaxFactory.List <StatementSyntax>(innermostStatements)).WithAdditionalAnnotations(Formatter.Annotation); var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var rewriter = new Rewriter(state.InnermostBlock, newInnermostBlock, state.OutermostBlock, state.DeclarationStatement); var newRoot = rewriter.Visit(tree.GetRoot(cancellationToken)); return(document.WithSyntaxRoot(newRoot)); }
private static async Task <Tuple <SemanticDocument, ISet <ExpressionSyntax> > > ComplexifyParentingStatements( SemanticDocument semanticDocument, ISet <ExpressionSyntax> matches, CancellationToken cancellationToken) { // First, track the matches so that we can get back to them later. var newRoot = semanticDocument.Root.TrackNodes(matches); var newDocument = semanticDocument.Document.WithSyntaxRoot(newRoot); var newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); var newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet(); // Next, expand the topmost parenting expression of each match, being careful // not to expand the matches themselves. var topMostExpressions = newMatches .Select(m => m.AncestorsAndSelf().OfType <ExpressionSyntax>().Last()) .Distinct(); newRoot = await newSemanticDocument.Root .ReplaceNodesAsync( topMostExpressions, computeReplacementAsync : async(oldNode, newNode, ct) => { return(await Simplifier .ExpandAsync( oldNode, newSemanticDocument.Document, expandInsideNode: node => { var expression = node as ExpressionSyntax; return expression == null || !newMatches.Contains(expression); }, cancellationToken: ct) .ConfigureAwait(false)); }, cancellationToken : cancellationToken) .ConfigureAwait(false); newDocument = newSemanticDocument.Document.WithSyntaxRoot(newRoot); newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet(); return(Tuple.Create(newSemanticDocument, newMatches)); }
private static async Task MoveDeclarationToFirstReferenceAsync( Document document, State state, SyntaxEditor editor, SyntaxAnnotation warningAnnotation, CancellationToken cancellationToken) { // If we're not merging with an existing declaration, make the declaration semantically // explicit to improve the chances that it won't break code. var explicitDeclarationStatement = await Simplifier.ExpandAsync( state.DeclarationStatement, document, cancellationToken : cancellationToken).ConfigureAwait(false); // place the declaration above the first statement that references it. var declarationStatement = warningAnnotation == null ? explicitDeclarationStatement : explicitDeclarationStatement.WithAdditionalAnnotations(warningAnnotation); declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation); var bannerService = document.GetRequiredLanguageService <IFileBannerFactsService>(); var newNextStatement = state.FirstStatementAffectedInInnermostBlock; declarationStatement = declarationStatement.WithPrependedLeadingTrivia( bannerService.GetLeadingBlankLines(newNextStatement)); editor.InsertBefore( state.FirstStatementAffectedInInnermostBlock, declarationStatement); editor.ReplaceNode( newNextStatement, newNextStatement.WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia( bannerService.GetTriviaAfterLeadingBlankLines(newNextStatement))); // Move leading whitespace from the declaration statement to the next statement. var statementIndex = state.OutermostBlockStatements.IndexOf(state.DeclarationStatement); if (statementIndex + 1 < state.OutermostBlockStatements.Count) { var originalNextStatement = state.OutermostBlockStatements[statementIndex + 1]; editor.ReplaceNode( originalNextStatement, (current, generator) => current.WithAdditionalAnnotations(Formatter.Annotation).WithPrependedLeadingTrivia( bannerService.GetLeadingBlankLines(state.DeclarationStatement))); } }
private async Task <ExpressionSyntax> CreateExpressionToInlineAsync( VariableDeclaratorSyntax variableDeclarator, Document document, CancellationToken cancellationToken) { var updatedDocument = document; var expression = SkipRedundantExteriorParentheses(variableDeclarator.Initializer.Value); var semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken); var newExpression = InitializerRewriter.Visit(expression, localSymbol, semanticModel); // If this is an array initializer, we need to transform it into an array creation // expression for inlining. if (newExpression.Kind() == SyntaxKind.ArrayInitializerExpression) { var arrayType = (ArrayTypeSyntax)localSymbol.Type.GenerateTypeSyntax(); var arrayInitializer = (InitializerExpressionSyntax)newExpression; // Add any non-whitespace trailing trivia from the equals clause to the type. var equalsToken = variableDeclarator.Initializer.EqualsToken; if (equalsToken.HasTrailingTrivia) { var trailingTrivia = equalsToken.TrailingTrivia.SkipInitialWhitespace(); if (trailingTrivia.Any()) { arrayType = arrayType.WithTrailingTrivia(trailingTrivia); } } newExpression = SyntaxFactory.ArrayCreationExpression(arrayType, arrayInitializer); } newExpression = newExpression.WithAdditionalAnnotations(InitializerAnnotation); updatedDocument = await updatedDocument.ReplaceNodeAsync(variableDeclarator.Initializer.Value, newExpression, cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newExpression = await FindInitializerAsync(updatedDocument, cancellationToken).ConfigureAwait(false); var newVariableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(newVariableDeclarator, cancellationToken); bool wasCastAdded; var explicitCastExpression = newExpression.CastIfPossible(localSymbol.Type, newVariableDeclarator.SpanStart, semanticModel, out wasCastAdded); if (wasCastAdded) { updatedDocument = await updatedDocument.ReplaceNodeAsync(newExpression, explicitCastExpression, cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newVariableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); } // Now that the variable declarator is normalized, make its initializer // value semantically explicit. newExpression = await Simplifier.ExpandAsync(newVariableDeclarator.Initializer.Value, updatedDocument, cancellationToken : cancellationToken).ConfigureAwait(false); return(newExpression.WithAdditionalAnnotations(ExpressionToInlineAnnotation)); }
SyntaxNode Expand(SyntaxNode node) => Simplifier.ExpandAsync(node, document).Result; //? async-counterpart?