private async Task<Document> FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Create an editor to do all the transformations. This allows us to fix all // the diagnostics in a clean manner. If we used the normal batch fix provider // then it might fail to apply all the individual text changes as many of the // changes produced by the diff might end up overlapping others. var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var options = document.Project.Solution.Workspace.Options; // Attempt to use an out-var declaration if that's the style the user prefers. // Note: if using 'var' would cause a problem, we will use the actual type // of hte local. This is necessary in some cases (for example, when the // type of the out-var-decl affects overload resolution or generic instantiation). var useVarWhenDeclaringLocals = options.GetOption(CSharpCodeStyleOptions.UseVarWhenDeclaringLocals); var useImplicitTypeForIntrinsicTypes = options.GetOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes).Value; foreach (var diagnostic in diagnostics) { cancellationToken.ThrowIfCancellationRequested(); await AddEditsAsync(document, editor, diagnostic, useVarWhenDeclaringLocals, useImplicitTypeForIntrinsicTypes, cancellationToken).ConfigureAwait(false); } var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
private async Task HandleDeclarationAsync( Document document, SyntaxEditor editor, SyntaxNode node, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var declarationContext = node.Parent; TypeSyntax typeSyntax = null; if (declarationContext is VariableDeclarationSyntax) { typeSyntax = ((VariableDeclarationSyntax)declarationContext).Type; } else if (declarationContext is ForEachStatementSyntax) { typeSyntax = ((ForEachStatementSyntax)declarationContext).Type; } else { Contract.Fail($"unhandled kind {declarationContext.Kind().ToString()}"); } var typeSymbol = semanticModel.GetTypeInfo(typeSyntax).ConvertedType; var typeName = typeSymbol.GenerateTypeSyntax() .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); Debug.Assert(!typeName.ContainsDiagnostics, "Explicit type replacement likely introduced an error in code"); editor.ReplaceNode(node, typeName); }
private void HandleSingleIfStatementForm( SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) { var ifStatementLocation = diagnostic.AdditionalLocations[0]; var expressionStatementLocation = diagnostic.AdditionalLocations[1]; var ifStatement = (IfStatementSyntax)root.FindNode(ifStatementLocation.SourceSpan); cancellationToken.ThrowIfCancellationRequested(); var expressionStatement = (ExpressionStatementSyntax)root.FindNode(expressionStatementLocation.SourceSpan); cancellationToken.ThrowIfCancellationRequested(); var invocationExpression = (InvocationExpressionSyntax)expressionStatement.Expression; cancellationToken.ThrowIfCancellationRequested(); StatementSyntax newStatement = expressionStatement.WithExpression( SyntaxFactory.ConditionalAccessExpression( invocationExpression.Expression, SyntaxFactory.InvocationExpression( SyntaxFactory.MemberBindingExpression(SyntaxFactory.IdentifierName(nameof(Action.Invoke))), invocationExpression.ArgumentList))); newStatement = newStatement.WithPrependedLeadingTrivia(ifStatement.GetLeadingTrivia()); if (ifStatement.Parent.IsKind(SyntaxKind.ElseClause) && ifStatement.Statement.IsKind(SyntaxKind.Block)) { newStatement = ((BlockSyntax)ifStatement.Statement).WithStatements(SyntaxFactory.SingletonList(newStatement)); } newStatement = newStatement.WithAdditionalAnnotations(Formatter.Annotation); cancellationToken.ThrowIfCancellationRequested(); editor.ReplaceNode(ifStatement, newStatement); }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); var generator = editor.Generator; var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var conditionalExpression = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); var conditionExpression = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var whenPart = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); syntaxFacts.GetPartsOfConditionalExpression( conditionalExpression, out var condition, out var whenTrue, out var whenFalse); editor.ReplaceNode(conditionalExpression, (c, g) => { syntaxFacts.GetPartsOfConditionalExpression( c, out var currentCondition, out var currentWhenTrue, out var currentWhenFalse); return whenPart == whenTrue ? g.CoalesceExpression(conditionExpression, syntaxFacts.WalkDownParentheses(currentWhenTrue)) : g.CoalesceExpression(conditionExpression, syntaxFacts.WalkDownParentheses(currentWhenFalse)); }); } return SpecializedTasks.EmptyTask; }
private async Task<Document> FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var generator = editor.Generator; foreach (var diagnostic in diagnostics) { var ifStatement = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan); var throwStatementExpression = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var assignmentValue = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); // First, remote the if-statement entirely. editor.RemoveNode(ifStatement); // Now, update the assignemnt value to go from 'a' to 'a ?? throw ...'. editor.ReplaceNode(assignmentValue, generator.CoalesceExpression(assignmentValue, generator.ThrowExpression(throwStatementExpression))); } var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
private void AddEdits( SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) { var localDeclarationLocation = diagnostic.AdditionalLocations[0]; var ifStatementLocation = diagnostic.AdditionalLocations[1]; var conditionLocation = diagnostic.AdditionalLocations[2]; var asExpressionLocation = diagnostic.AdditionalLocations[3]; var localDeclaration = (LocalDeclarationStatementSyntax)localDeclarationLocation.FindNode(cancellationToken); var ifStatement = (IfStatementSyntax)ifStatementLocation.FindNode(cancellationToken); var condition = (BinaryExpressionSyntax)conditionLocation.FindNode(cancellationToken); var asExpression = (BinaryExpressionSyntax)asExpressionLocation.FindNode(cancellationToken); var updatedCondition = SyntaxFactory.IsPatternExpression( asExpression.Left, SyntaxFactory.DeclarationPattern( ((TypeSyntax)asExpression.Right).WithoutTrivia(), localDeclaration.Declaration.Variables[0].Identifier.WithoutTrivia())); var trivia = localDeclaration.GetLeadingTrivia().Concat(localDeclaration.GetTrailingTrivia()) .Where(t => t.IsSingleOrMultiLineComment()) .SelectMany(t => ImmutableArray.Create(t, SyntaxFactory.ElasticCarriageReturnLineFeed)) .ToImmutableArray(); var updatedIfStatement = ifStatement.ReplaceNode(condition, updatedCondition) .WithPrependedLeadingTrivia(trivia) .WithAdditionalAnnotations(Formatter.Annotation); editor.RemoveNode(localDeclaration); editor.ReplaceNode(ifStatement, updatedIfStatement); }
protected override async Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); await HandleDeclarationAsync(document, editor, node, cancellationToken).ConfigureAwait(false); } }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { foreach (var diagnostic in diagnostics) { cancellationToken.ThrowIfCancellationRequested(); AddEdits(editor, diagnostic, cancellationToken); } return SpecializedTasks.EmptyTask; }
private void AddEdits( SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) { if (diagnostic.Properties[Constants.Kind] == Constants.VariableAndIfStatementForm) { HandleVariableAndIfStatementForm(root, editor, diagnostic, cancellationToken); } else { Debug.Assert(diagnostic.Properties[Constants.Kind] == Constants.SingleIfStatementForm); HandleSingleIfStatementForm(root, editor, diagnostic, cancellationToken); } }
protected async Task<Document> FixAllWithEditorAsync( Document document, Func<SyntaxEditor, Task> editAsync, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); await editAsync(editor).ConfigureAwait(false); var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var baseFieldDeclaration = (BaseFieldDeclarationSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); List<BaseFieldDeclarationSyntax> newFieldDeclarations = SplitDeclaration(baseFieldDeclaration); if (newFieldDeclarations != null) { var editor = new SyntaxEditor(syntaxRoot, document.Project.Solution.Workspace); editor.InsertAfter(baseFieldDeclaration, newFieldDeclarations); editor.RemoveNode(baseFieldDeclaration); return document.WithSyntaxRoot(editor.GetChangedRoot().WithoutFormatting()); } return document; }
private async Task<Document> FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); foreach (var diagnostic in diagnostics) { cancellationToken.ThrowIfCancellationRequested(); AddEdits(root, editor, diagnostic, cancellationToken); } var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var implicitType = SyntaxFactory.IdentifierName("var") .WithTriviaFrom(node); editor.ReplaceNode(node, implicitType); } return SpecializedTasks.EmptyTask; }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var statement = root.FindNode(diagnostic.Location.SourceSpan); // Use the callback version of ReplaceNode so that we see the effects // of other replace calls. i.e. we may have statements nested in statements, // we need to make sure that any inner edits are seen when we make the outer // replacement. editor.ReplaceNode(statement, (s, g) => GetReplacementNode(s)); } return SpecializedTasks.EmptyTask; }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var root = editor.OriginalRoot; var generator = editor.Generator; foreach (var diagnostic in diagnostics) { var oldNameNode = diagnostic.Location.FindNode( getInnermostNodeForTie: true, cancellationToken: cancellationToken); var preferredName = diagnostic.Properties[nameof(UseExplicitTupleNameDiagnosticAnalyzer.ElementName)]; var newNameNode = generator.IdentifierName(preferredName).WithTriviaFrom(oldNameNode); editor.ReplaceNode(oldNameNode, newNameNode); } return SpecializedTasks.EmptyTask; }
private void AddEdits( SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) { var ifStatementLocation = diagnostic.AdditionalLocations[0]; var localDeclarationLocation = diagnostic.AdditionalLocations[1]; var ifStatement = (IfStatementSyntax)ifStatementLocation.FindNode(cancellationToken); var localDeclaration = (LocalDeclarationStatementSyntax)localDeclarationLocation.FindNode(cancellationToken); var isExpression = (BinaryExpressionSyntax)ifStatement.Condition; var updatedCondition = SyntaxFactory.IsPatternExpression( isExpression.Left, SyntaxFactory.DeclarationPattern( ((TypeSyntax)isExpression.Right).WithoutTrivia(), Extensions.SyntaxTokenExtensions.WithoutTrivia( localDeclaration.Declaration.Variables[0].Identifier))); var trivia = localDeclaration.GetLeadingTrivia().Concat(localDeclaration.GetTrailingTrivia()) .Where(t => t.IsSingleOrMultiLineComment()) .SelectMany(t => ImmutableArray.Create(t, SyntaxFactory.ElasticCarriageReturnLineFeed)) .ToImmutableArray(); var updatedIfStatement = ifStatement.ReplaceNode(ifStatement.Condition, updatedCondition) .WithPrependedLeadingTrivia(trivia) .WithAdditionalAnnotations(Formatter.Annotation); editor.RemoveNode(localDeclaration); editor.ReplaceNode(ifStatement, (i, g) => { // Because the local declaration is *inside* the 'if', we need to get the 'if' // statement after it was already modified and *then* update the condition // portion of it. var currentIf = (IfStatementSyntax)i; return currentIf.ReplaceNode(currentIf.Condition, updatedCondition) .WithPrependedLeadingTrivia(trivia) .WithAdditionalAnnotations(Formatter.Annotation); }); }
private async Task<Document> FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken) { var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var generator = editor.Generator; foreach (var diagnostic in diagnostics) { var conditionalExpression = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); var conditionalPartHigh = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var whenPart = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); SyntaxNode condition, whenTrue, whenFalse; syntaxFacts.GetPartsOfConditionalExpression( conditionalExpression, out condition, out whenTrue, out whenFalse); var conditionalPartLow = syntaxFacts.WalkDownParentheses(conditionalPartHigh); editor.ReplaceNode(conditionalExpression, (c, g) => { SyntaxNode currentCondition, currentWhenTrue, currentWhenFalse; syntaxFacts.GetPartsOfConditionalExpression( c, out currentCondition, out currentWhenTrue, out currentWhenFalse); return whenPart == whenTrue ? g.CoalesceExpression(conditionalPartLow, syntaxFacts.WalkDownParentheses(currentWhenTrue)) : g.CoalesceExpression(conditionalPartLow, syntaxFacts.WalkDownParentheses(currentWhenFalse)); }); } var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var generator = editor.Generator; var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var ifStatement = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan); var throwStatementExpression = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var assignmentValue = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); // First, remote the if-statement entirely. editor.RemoveNode(ifStatement); // Now, update the assignemnt value to go from 'a' to 'a ?? throw ...'. editor.ReplaceNode(assignmentValue, generator.CoalesceExpression(assignmentValue, generator.ThrowExpression(throwStatementExpression))); } return SpecializedTasks.EmptyTask; }
public static void SetExpression(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode expression) { editor.ReplaceNode(declaration, (d, g) => g.WithExpression(d, expression)); }
public static void ApplyChanges(SyntaxNode invokationSyntax, SyntaxEditor editor, IReadOnlyCollection<Fields> invokedMethodsOfMocks) { var setups = MakeSetups(invokedMethodsOfMocks); var verifiers = MakeVerifiers(invokedMethodsOfMocks); editor.InsertBefore(invokationSyntax, setups.Select( (x, i) => setups.Length - 1 == i ? x.WithLeadingTrivia(SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker)) .WithTrailingTrivia(SyntaxFactory.TriviaList(SyntaxFactory.CarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed)) : x.WithLeadingTrivia(SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker)))); //todo will try to understand how to add a new line before editor.InsertAfter(invokationSyntax, verifiers.Select(x => x.WithLeadingTrivia(SyntaxFactory.ElasticMarker))); }
protected abstract Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken);
public static void InsertParameter(this SyntaxEditor editor, SyntaxNode declaration, int index, SyntaxNode parameter) => editor.ReplaceNode(declaration, (d, g) => g.InsertParameters(d, index, new[] { parameter }));
private void RemoveAwaitFromCallerIfPresent( SyntaxEditor editor, ISyntaxFactsService syntaxFacts, SyntaxNode root, ReferenceLocation referenceLocation, CancellationToken cancellationToken) { if (referenceLocation.IsImplicit) { return; } var location = referenceLocation.Location; var token = location.FindToken(cancellationToken); var nameNode = token.Parent; if (nameNode == null) { return; } // Look for the following forms: // await M(...) // await <expr>.M(...) // await M(...).ConfigureAwait(...) // await <expr>.M(...).ConfigureAwait(...) var expressionNode = nameNode; if (syntaxFacts.IsNameOfMemberAccessExpression(nameNode)) { expressionNode = nameNode.Parent; } if (!syntaxFacts.IsExpressionOfInvocationExpression(expressionNode)) { return; } // We now either have M(...) or <expr>.M(...) var invocationExpression = expressionNode.Parent; Debug.Assert(syntaxFacts.IsInvocationExpression(invocationExpression)); if (syntaxFacts.IsExpressionOfAwaitExpression(invocationExpression)) { // Handle the case where we're directly awaited. var awaitExpression = invocationExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression) .WithTriviaFrom(currentAwaitExpression)); } else if (syntaxFacts.IsExpressionOfMemberAccessExpression(invocationExpression)) { // Check for the .ConfigureAwait case. var parentMemberAccessExpression = invocationExpression.Parent; var parentMemberAccessExpressionNameNode = syntaxFacts.GetNameOfMemberAccessExpression( parentMemberAccessExpression); var parentMemberAccessExpressionName = syntaxFacts.GetIdentifierOfSimpleName(parentMemberAccessExpressionNameNode).ValueText; if (parentMemberAccessExpressionName == nameof(Task.ConfigureAwait)) { var parentExpression = parentMemberAccessExpression.Parent; if (syntaxFacts.IsExpressionOfAwaitExpression(parentExpression)) { var awaitExpression = parentExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => { var currentConfigureAwaitInvocation = syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression); var currentMemberAccess = syntaxFacts.GetExpressionOfInvocationExpression(currentConfigureAwaitInvocation); var currentInvocationExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(currentMemberAccess); return currentInvocationExpression.WithTriviaFrom(currentAwaitExpression); }); } } } }
public static void AddParameter( ISyntaxFacts syntaxFacts, SyntaxEditor editor, SyntaxNode declaration, int insertionIndex, SyntaxNode parameterDeclaration, CancellationToken cancellationToken) { var sourceText = declaration.SyntaxTree.GetText(cancellationToken); var generator = editor.Generator; var existingParameters = generator.GetParameters(declaration); var placeOnNewLine = ShouldPlaceParametersOnNewLine(existingParameters, cancellationToken); if (!placeOnNewLine) { // Trivial case. Just let the stock editor impl handle this for us. editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); return; } if (insertionIndex == existingParameters.Count) { // Placing the last parameter on its own line. Get the indentation of the // curent last parameter and give the new last parameter the same indentation. var leadingIndentation = GetDesiredLeadingIndentation( generator, syntaxFacts, existingParameters[existingParameters.Count - 1], includeLeadingNewLine: true); parameterDeclaration = parameterDeclaration.WithPrependedLeadingTrivia(leadingIndentation) .WithAdditionalAnnotations(Formatter.Annotation); editor.AddParameter(declaration, parameterDeclaration); } else if (insertionIndex == 0) { // Inserting into the start of the list. The existing first parameter might // be on the same line as the parameter list, or it might be on the next line. var firstParameter = existingParameters[0]; var previousToken = firstParameter.GetFirstToken().GetPreviousToken(); if (sourceText.AreOnSameLine(previousToken, firstParameter.GetFirstToken())) { // First parameter is on hte same line as the method. // We want to insert the parameter at the front of the existing parameter // list. That means we need to move the current first parameter to a new // line. Give the current first parameter the indentation of the second // parameter in the list. editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); var nextParameter = existingParameters[insertionIndex]; var nextLeadingIndentation = GetDesiredLeadingIndentation( generator, syntaxFacts, existingParameters[insertionIndex + 1], includeLeadingNewLine: true); editor.ReplaceNode( nextParameter, nextParameter.WithPrependedLeadingTrivia(nextLeadingIndentation) .WithAdditionalAnnotations(Formatter.Annotation)); } else { // First parameter is on its own line. No need to adjust its indentation. // Just copy its indentation over to the parameter we're inserting, and // make sure the current first parameter gets a newline so it stays on // its own line. // We want to insert the parameter at the front of the existing parameter // list. That means we need to move the current first parameter to a new // line. Give the current first parameter the indentation of the second // parameter in the list. var firstLeadingIndentation = GetDesiredLeadingIndentation( generator, syntaxFacts, existingParameters[0], includeLeadingNewLine: false); editor.InsertParameter(declaration, insertionIndex, parameterDeclaration.WithLeadingTrivia(firstLeadingIndentation)); var nextParameter = existingParameters[insertionIndex]; editor.ReplaceNode( nextParameter, nextParameter.WithPrependedLeadingTrivia(generator.ElasticCarriageReturnLineFeed) .WithAdditionalAnnotations(Formatter.Annotation)); } } else { // We're inserting somewhere after the start (but not at the end). Because // we've set placeOnNewLine, we know that the current comma we'll be placed // after already have a newline following it. So all we need for this new // parameter is to get the indentation of the following parameter. // Because we're going to 'steal' the existing comma from that parameter, // ensure that the next parameter has a new-line added to it so that it will // still stay on a new line. var nextParameter = existingParameters[insertionIndex]; var leadingIndentation = GetDesiredLeadingIndentation( generator, syntaxFacts, existingParameters[insertionIndex], includeLeadingNewLine: false); parameterDeclaration = parameterDeclaration.WithPrependedLeadingTrivia(leadingIndentation); editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); editor.ReplaceNode( nextParameter, nextParameter.WithPrependedLeadingTrivia(generator.ElasticCarriageReturnLineFeed) .WithAdditionalAnnotations(Formatter.Annotation)); } }
public static void InsertMembers(this SyntaxEditor editor, SyntaxNode declaration, int index, IEnumerable <SyntaxNode> members) { editor.ReplaceNode(declaration, (d, g) => g.InsertMembers(d, index, members)); }
internal static void RemoveAllComments(this SyntaxEditor editor, SyntaxNode declaration) => editor.ReplaceNode(declaration, (d, g) => g.RemoveAllComments(d));
public static void AddParameter(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode parameter) => editor.ReplaceNode(declaration, (d, g) => g.AddParameters(d, new[] { parameter }));
public static void AddMember(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode member) { editor.ReplaceNode(declaration, (d, g) => g.AddMembers(d, new[] { member })); }
public static void SetTypeParameters(this SyntaxEditor editor, SyntaxNode declaration, IEnumerable <string> typeParameters) { editor.ReplaceNode(declaration, (d, g) => g.WithTypeParameters(d, typeParameters)); }
public static void AddReturnAttribute(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode attribute) { editor.ReplaceNode(declaration, (d, g) => g.AddAttributes(d, new[] { attribute })); }
public static void SetSetAccessorStatements(this SyntaxEditor editor, SyntaxNode declaration, IEnumerable <SyntaxNode> statements) { editor.ReplaceNode(declaration, (d, g) => g.WithSetAccessorStatements(d, statements)); }
public static void SetName(this SyntaxEditor editor, SyntaxNode declaration, string name) => editor.ReplaceNode(declaration, (d, g) => g.WithName(d, name));
public static void AddInterfaceType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode interfaceType) { editor.ReplaceNode(declaration, (d, g) => g.AddInterfaceType(d, interfaceType)); }
internal static void RemoveAllTypeInheritance(this SyntaxEditor editor, SyntaxNode declaration) => editor.ReplaceNode(declaration, (d, g) => g.RemoveAllTypeInheritance(d));
public static void AddBaseType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode baseType) { editor.ReplaceNode(declaration, (d, g) => g.AddBaseType(d, baseType)); }
private async Task<Solution> RemoveAwaitFromCallersAsync( Solution currentSolution, IGrouping<Document, ReferenceLocation> group, CancellationToken cancellationToken) { var document = group.Key; var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, currentSolution.Workspace); foreach (var location in group) { RemoveAwaitFromCallerIfPresent(editor, syntaxFactsService, root, location, cancellationToken); } var newRoot = editor.GetChangedRoot(); return currentSolution.WithDocumentSyntaxRoot(document.Id, newRoot); }
private void FixOneDiagnostic( Document document, SyntaxEditor editor, SemanticModel model, Diagnostic diagnostic, bool addCases, bool addDefaultCase, bool onlyOneDiagnostic, CancellationToken cancellationToken) { var hasMissingCases = bool.Parse(diagnostic.Properties[PopulateSwitchHelpers.MissingCases]); var hasMissingDefaultCase = bool.Parse(diagnostic.Properties[PopulateSwitchHelpers.MissingDefaultCase]); var switchNode = diagnostic.Location.FindNode(cancellationToken); var internalMethod = typeof(SemanticModel).GetTypeInfo().GetDeclaredMethod("GetOperationInternal"); var switchStatement = (ISwitchStatement)internalMethod.Invoke(model, new object[] { switchNode, cancellationToken }); var enumType = switchStatement.Value.Type; var generator = editor.Generator; var sectionStatements = new[] { generator.ExitSwitchStatement() }; var newSections = new List<SyntaxNode>(); if (hasMissingCases && addCases) { var missingEnumMembers = PopulateSwitchHelpers.GetMissingEnumMembers(switchStatement); var missingSections = from e in missingEnumMembers let caseLabel = generator.MemberAccessExpression(generator.TypeExpression(enumType), e.Name).WithAdditionalAnnotations(Simplifier.Annotation) let section = generator.SwitchSection(caseLabel, sectionStatements) select section; newSections.AddRange(missingSections); } if (hasMissingDefaultCase && addDefaultCase) { // Always add the default clause at the end. newSections.Add(generator.DefaultSwitchSection(sectionStatements)); } var insertLocation = InsertPosition(switchStatement); var newSwitchNode = generator.InsertSwitchSections(switchNode, insertLocation, newSections) .WithAdditionalAnnotations(Formatter.Annotation); if (onlyOneDiagnostic) { // If we're only fixing up one issue in this document, then also make sure we // didn't cause any braces to be imbalanced when we added members to the switch. // Note: i'm only doing this for the single case because it feels too complex // to try to support this during fix-all. var root = editor.OriginalRoot; AddMissingBraces(document, ref root, ref switchNode); var newRoot = root.ReplaceNode(switchNode, newSwitchNode); editor.ReplaceNode(editor.OriginalRoot, newRoot); } else { editor.ReplaceNode(switchNode, newSwitchNode); } }
public static void SetModifiers(this SyntaxEditor editor, SyntaxNode declaration, DeclarationModifiers modifiers) => editor.ReplaceNode(declaration, (d, g) => g.WithModifiers(d, modifiers));
protected override Task FixAllAsync( Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { // If the user is performing a fix-all, then fix up all the issues we see. i.e. // add missing cases and missing 'default' cases for any switches we reported an // issue on. return FixWithEditorAsync(document, editor, diagnostics, addCases: true, addDefaultCase: true, cancellationToken: cancellationToken); }
internal static void RemoveAllAttributes(this SyntaxEditor editor, SyntaxNode declaration) { editor.ReplaceNode(declaration, (d, g) => g.RemoveAllAttributes(d)); }
private async Task FixWithEditorAsync( Document document, SyntaxEditor editor, ImmutableArray<Diagnostic> diagnostics, bool addCases, bool addDefaultCase, CancellationToken cancellationToken) { var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); foreach (var diagnostic in diagnostics) { FixOneDiagnostic( document, editor, model, diagnostic, addCases, addDefaultCase, diagnostics.Length == 1, cancellationToken); } }
private static Document HandVariableAndIfStatementFormAsync( Document document, SyntaxNode root, Diagnostic diagnostic, CancellationToken cancellationToken) { var localDeclarationLocation = diagnostic.AdditionalLocations[0]; var ifStatementLocation = diagnostic.AdditionalLocations[1]; var expressionStatementLocation = diagnostic.AdditionalLocations[2]; var localDeclarationStatement = (LocalDeclarationStatementSyntax)root.FindNode(localDeclarationLocation.SourceSpan); cancellationToken.ThrowIfCancellationRequested(); var ifStatement = (IfStatementSyntax)root.FindNode(ifStatementLocation.SourceSpan); cancellationToken.ThrowIfCancellationRequested(); var expressionStatement = (ExpressionStatementSyntax)root.FindNode(expressionStatementLocation.SourceSpan); cancellationToken.ThrowIfCancellationRequested(); var invocationExpression = (InvocationExpressionSyntax)expressionStatement.Expression; var parentBlock = (BlockSyntax)localDeclarationStatement.Parent; var newStatement = expressionStatement.WithExpression( SyntaxFactory.ConditionalAccessExpression( localDeclarationStatement.Declaration.Variables[0].Initializer.Value.Parenthesize(), SyntaxFactory.InvocationExpression( SyntaxFactory.MemberBindingExpression(SyntaxFactory.IdentifierName(nameof(Action.Invoke))), invocationExpression.ArgumentList))); newStatement = newStatement.WithAdditionalAnnotations(Formatter.Annotation); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); editor.ReplaceNode(ifStatement, newStatement); editor.RemoveNode(localDeclarationStatement, SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.AddElasticMarker); cancellationToken.ThrowIfCancellationRequested(); var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); }
public static void SetType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode type) { editor.ReplaceNode(declaration, (d, g) => g.WithType(d, type)); }
public static void AddAttributeArgument(this SyntaxEditor editor, SyntaxNode attributeDeclaration, SyntaxNode attributeArgument) { editor.ReplaceNode(attributeDeclaration, (d, g) => g.AddAttributeArguments(d, new[] { attributeArgument })); }
public static void SetTypeConstraint(this SyntaxEditor editor, SyntaxNode declaration, string typeParameterName, SpecialTypeConstraintKind kind, IEnumerable <SyntaxNode> types) { editor.ReplaceNode(declaration, (d, g) => g.WithTypeConstraint(d, typeParameterName, kind, types)); }
private async Task AddEditsAsync( Document document, SyntaxEditor editor, Diagnostic diagnostic, bool useVarWhenDeclaringLocals, bool useImplicitTypeForIntrinsicTypes, CancellationToken cancellationToken) { var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); // Recover the nodes we care about. var declaratorLocation = diagnostic.AdditionalLocations[0]; var identifierLocation = diagnostic.AdditionalLocations[1]; var invocationOrCreationLocation = diagnostic.AdditionalLocations[2]; var outArgumentContainingStatementLocation = diagnostic.AdditionalLocations[3]; var root = declaratorLocation.SourceTree.GetRoot(cancellationToken); var declarator = (VariableDeclaratorSyntax)declaratorLocation.FindNode(cancellationToken); var identifier = (IdentifierNameSyntax)identifierLocation.FindNode(cancellationToken); var invocationOrCreation = (ExpressionSyntax)invocationOrCreationLocation.FindNode( getInnermostNodeForTie: true, cancellationToken: cancellationToken); var outArgumentContainingStatement = (StatementSyntax)outArgumentContainingStatementLocation.FindNode(cancellationToken); var declaration = (VariableDeclarationSyntax)declarator.Parent; var singleDeclarator = declaration.Variables.Count == 1; if (singleDeclarator) { // This was a local statement with a single variable in it. Just Remove // the entire local declaration statement. Note that comments belonging to // this local statement will be moved to be above the statement containing // the out-var. editor.RemoveNode(declaration.Parent); } else { // Otherwise, just remove the single declarator. Note: we'll move the comments // 'on' the declarator to the out-var location. This is a little bit trickier // than normal due to how our comment-association rules work. i.e. if you have: // // var /*c1*/ i /*c2*/, /*c3*/ j /*c4*/; // // In this case 'c1' is owned by the 'var' token, not 'i', and 'c3' is owned by // the comment token not 'j'. editor.RemoveNode(declarator); if (declarator == declaration.Variables[0]) { // If we're removing the first declarator, and it's on the same line // as the previous token, then we want to remove all the trivia belonging // to the previous token. We're going to move it along with this declarator. // If we don't, then the comment will stay with the previous token. // // Note that hte moving of the comment happens later on when we make the // declaration expression. if (sourceText.AreOnSameLine(declarator.GetFirstToken(), declarator.GetFirstToken().GetPreviousToken(includeSkipped: true))) { editor.ReplaceNode( declaration.Type, (t, g) => t.WithTrailingTrivia(SyntaxFactory.ElasticSpace).WithoutAnnotations(Formatter.Annotation)); } } } // get the type that we want to put in the out-var-decl based on the user's options. // i.e. prefer 'out var' if that is what the user wants. var newType = this.GetDeclarationType(declaration.Type, useVarWhenDeclaringLocals, useImplicitTypeForIntrinsicTypes); var declarationExpression = GetDeclarationExpression( sourceText, identifier, newType, singleDeclarator ? null : declarator); // Check if using out-var changed problem semantics. var semanticsChanged = await SemanticsChangedAsync( document, declaration, invocationOrCreation, newType, identifier, declarationExpression, cancellationToken).ConfigureAwait(false); if (semanticsChanged) { // Switching to 'var' changed semantics. Just use the original type of the local. var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var local = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator); // If the user originally wrote it something other than 'var', then use what they // wrote. Otherwise, synthesize the actual type of the local. var explicitType = declaration.Type.IsVar ? local.Type?.GenerateTypeSyntax() : declaration.Type; declarationExpression = GetDeclarationExpression( sourceText, identifier, explicitType, singleDeclarator ? null : declarator); } editor.ReplaceNode(identifier, declarationExpression); if (declaration.Variables.Count == 1) { // If we're removing the declaration entirely, move the leading/trailing comments it // had to sit above the statement containing the out-var declaration. var comments = declaration.Parent.GetLeadingTrivia().Concat(declaration.Parent.GetTrailingTrivia()) .Where(t => t.IsSingleOrMultiLineComment()) .SelectMany(t => ImmutableArray.Create(t, SyntaxFactory.ElasticCarriageReturnLineFeed)) .ToImmutableArray(); if (comments.Length > 0) { editor.ReplaceNode( outArgumentContainingStatement, (s, g) => s.WithPrependedLeadingTrivia(comments).WithAdditionalAnnotations(Formatter.Annotation)); } } }
public static void SetAccessibility(this SyntaxEditor editor, SyntaxNode declaration, Accessibility accessibility) { editor.ReplaceNode(declaration, (d, g) => g.WithAccessibility(d, accessibility)); }