private async static Task <Document> UseIndexerLast(Document document, SyntaxNode nodeToFix, CancellationToken cancellationToken) { var expression = GetParentMemberExpression(nodeToFix); if (expression == null) { return(document); } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var operation = semanticModel.GetOperation(nodeToFix, cancellationToken) as IInvocationOperation; if (operation == null) { return(document); } var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; var newExpression = generator.ElementAccessExpression(operation.Arguments[0].Syntax, generator.SubtractExpression( generator.MemberAccessExpression(operation.Arguments[0].Syntax, GetMemberName()), generator.LiteralExpression(1))); editor.ReplaceNode(nodeToFix, newExpression); return(editor.GetChangedDocument()); string GetMemberName() { var type = operation.Arguments[0].Value.GetActualType(); var isArray = type != null && type.TypeKind == TypeKind.Array; if (isArray) { return("Length"); } return("Count"); } }
private static async Task <Document> SplitAddOperator(Document document, SyntaxNode nodeToFix, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; var operation = (IInvocationOperation)editor.SemanticModel.GetOperation(nodeToFix, cancellationToken); var methodName = operation.TargetMethod.Name; // Append or AppendLine bool isAppendLine = string.Equals(methodName, nameof(StringBuilder.AppendLine), StringComparison.Ordinal); var binaryOperation = (IBinaryOperation)operation.Arguments[0].Value; var newExpression = generator.InvocationExpression(generator.MemberAccessExpression(operation.Children.First().Syntax, "Append"), binaryOperation.LeftOperand.Syntax); newExpression = generator.InvocationExpression(generator.MemberAccessExpression(newExpression, isAppendLine ? "AppendLine" : "Append"), binaryOperation.RightOperand.Syntax); editor.ReplaceNode(nodeToFix, newExpression); return(editor.GetChangedDocument()); }
private static async Task <Document> ApplyFix(Document document, TextSpan span, CancellationToken cancellationToken) { var root = await document .GetSyntaxRootAsync(cancellationToken) .ConfigureAwait(false); var argumentListSyntax = root.FindNode(span) .FirstAncestorOrSelf <ArgumentListSyntax>(); var newArgumentListSyntax = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { argumentListSyntax.Arguments[0] })); var editor = await DocumentEditor.CreateAsync(document, cancellationToken); editor.ReplaceNode(argumentListSyntax, newArgumentListSyntax); return(editor.GetChangedDocument()); }
private static async Task <Document> RemoveTypeofInvocationAndAddGenericTypeAsync(Document document, InvocationExpressionSyntax invocation, MemberAccessExpressionSyntax memberAccess, TypeOfExpressionSyntax typeOfExpression, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); editor.ReplaceNode(invocation, invocation .WithExpression(memberAccess .WithName( SyntaxFactory.GenericName( memberAccess.Name.Identifier, SyntaxFactory.TypeArgumentList( SyntaxFactory.SingletonSeparatedList(typeOfExpression.Type))))) .WithArgumentList( invocation.ArgumentList .WithArguments(invocation.ArgumentList.Arguments.RemoveAt(0)))); return(editor.GetChangedDocument()); }
private static async Task <Document> MakeConstructorProtected(Document document, SyntaxNode nodeToFix, string comparerName, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var generator = editor.Generator; var syntax = (MemberAccessExpressionSyntax)nodeToFix; var stringComparer = semanticModel.Compilation.GetTypeByMetadataName("System.StringComparer"); var newSyntax = generator.MemberAccessExpression( generator.TypeExpression(stringComparer), comparerName); editor.ReplaceNode(syntax, newSyntax); return(editor.GetChangedDocument()); }
private static async Task <Document> ReplaceWithAppendFormat(Document document, SyntaxNode nodeToFix, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; var operation = (IInvocationOperation?)editor.SemanticModel.GetOperation(nodeToFix, cancellationToken); if (operation == null) { return(document); } var methodName = operation.TargetMethod.Name; // Append or AppendLine var isAppendLine = string.Equals(methodName, nameof(StringBuilder.AppendLine), StringComparison.Ordinal); var toStringOperation = (IInvocationOperation)operation.Arguments[0].Value; var newExpression = generator.InvocationExpression(generator.MemberAccessExpression(operation.Children.First().Syntax, "AppendFormat"), toStringOperation.Arguments[1].Syntax, GetFormatExpression(toStringOperation.Arguments[0].Value), toStringOperation.Children.First().Syntax); if (isAppendLine) { newExpression = generator.InvocationExpression(generator.MemberAccessExpression(newExpression, "AppendLine")); } editor.ReplaceNode(nodeToFix, newExpression); return(editor.GetChangedDocument()); SyntaxNode GetFormatExpression(IOperation formatOperation) { if (formatOperation.ConstantValue.HasValue) { return(generator.LiteralExpression("{0:" + (string?)formatOperation.ConstantValue.Value + "}")); } return(generator.AddExpression(generator.AddExpression( generator.LiteralExpression("{0:"), formatOperation.Syntax), generator.LiteralExpression("}"))); } }
private async Task <Solution> ChangeEnumValueAsync( Document document, EnumMemberDeclarationSyntax valueDeclaration, HashSet <int> values, SemanticModel model, CancellationToken cancellationToken) { var symbol = model.GetDeclaredSymbol(valueDeclaration); var newValue = Enumerable.Range(1, int.MaxValue).Where(EnumValuesUtility.IsPowerOfTwo).Where(x => !values.Contains(x)).First(); var expression = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression); expression = expression.WithToken(SyntaxFactory.Literal(newValue)); var editor = await DocumentEditor.CreateAsync(document, cancellationToken); editor.ReplaceNode(valueDeclaration, valueDeclaration.WithEqualsValue(SyntaxFactory.EqualsValueClause(expression))); return(editor.GetChangedDocument().Project.Solution); }
public static async Task <BrpMagicStringsResult> Solve(string text) { using (var workspace = new AdhocWorkspace()) { var projectInfo = ProjectInfo.Create( ProjectId.CreateNewId(), VersionStamp.Create(), "NewProject", "projName", LanguageNames.CSharp); var newProject = workspace.AddProject(projectInfo); var document = workspace.AddDocument(newProject.Id, "NewFile.cs", SourceText.From(text)); var syntaxRoot = await document.GetSyntaxRootAsync(); var editor = await DocumentEditor.CreateAsync(document); var stats = new MagicStringsReplacementStatistics(); foreach (var classNode in syntaxRoot.DescendantNodes().OfType <ClassDeclarationSyntax>()) { var existingConstants = AnalyzeExistingConstants(classNode); var constantsFromCode = AnalyzeMagicStrings(classNode); var constantsToCreate = constantsFromCode .Where(c => !existingConstants.ContainsKey(c)) .ToList(); var newConstants = CreateConstants(constantsToCreate, classNode, editor); stats.ConstantsCreated += newConstants.Count; var allConstants = existingConstants .Concat(newConstants) .ToDictionary(kv => kv.Key, kv => kv.Value); ReplaceMagicStrings(allConstants, classNode, editor, stats); } var newDocument = editor.GetChangedDocument(); var sourceText = await newDocument.GetTextAsync(); return(new BrpMagicStringsResult(sourceText.ToString(), stats)); } }
public IMultipleTarget <TSyntaxNode0, TSyntaxNode1> Select <TSyntaxNode0, TSyntaxNode1>() where TSyntaxNode0 : CSharpSyntaxNode where TSyntaxNode1 : CSharpSyntaxNode { var allTargets = Enumerable.Empty <CSharpSingleTarget <TSyntaxNode0, TSyntaxNode1> >(); foreach (var id in CurrentProject.DocumentIds) { var doc = CurrentProject.GetDocument(id); var editor = DocumentEditor.CreateAsync(doc).Result; var root = editor.OriginalRoot as CSharpSyntaxNode; var selector = new SelectSyntaxRewriter <TSyntaxNode0, TSyntaxNode1>(this, doc.FilePath); var newRoot = selector.VisitRoot(root); allTargets = allTargets.Concat(selector.Result); editor.ReplaceNode(root, newRoot); this.CurrentProject = editor.GetChangedDocument().Project; } return(new MultipleTarget <TSyntaxNode0, TSyntaxNode1>(allTargets)); }
private static async Task <Document> ApplyAddUsingFixAsync(CodeFixContext context, LocalDeclarationStatementSyntax statement) { var editor = await DocumentEditor.CreateAsync(context.Document).ConfigureAwait(false); var statements = statement.FirstAncestor <BlockSyntax>().Statements.Where(s => s.SpanStart > statement.SpanStart); foreach (var statementSyntax in statements) { editor.RemoveNode(statementSyntax); } editor.ReplaceNode( statement, SyntaxFactory.UsingStatement( declaration: statement.Declaration, expression: null, statement: SyntaxFactory.Block(SyntaxFactory.List(statements)))); return(editor.GetChangedDocument()); }
private async Task <Document> ChangeEnumTypeToInt32Async(Document document, Diagnostic diagnostic, SyntaxNode root, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; // Find syntax node that declares the enum var diagnosticSpan = diagnostic.Location.SourceSpan; var node = root.FindNode(diagnosticSpan); var enumDeclarationNode = generator.GetDeclaration(node, DeclarationKind.Enum); // Find the target syntax node to replace. Was not able to find a language neutral way of doing this. So using the language specific methods var targetNode = GetTargetNode(enumDeclarationNode); // Remove target node editor.RemoveNode(targetNode, SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.KeepTrailingTrivia | SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepEndOfLine); return(editor.GetChangedDocument()); }
private static async Task <Document> ReplaceWithNameOf(Document document, SyntaxNode nodeToReplace, string stringText, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; var trailingTrivia = nodeToReplace.GetTrailingTrivia(); var leadingTrivia = nodeToReplace.GetLeadingTrivia(); var nameOfExpression = generator.NameOfExpression(generator.IdentifierName(stringText)) .WithTrailingTrivia(trailingTrivia) .WithLeadingTrivia(leadingTrivia); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newRoot = root.ReplaceNode(nodeToReplace, nameOfExpression); return(document.WithSyntaxRoot(newRoot)); }
public async Task SystemWhenEmpty() { var testCode = @" namespace RoslynSandbox { }"; var sln = CodeFactory.CreateSolution(testCode); var editor = await DocumentEditor.CreateAsync(sln.Projects.First().Documents.First()).ConfigureAwait(false); var expected = @" namespace RoslynSandbox { using System; }"; var usingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System")); editor.AddUsing(usingDirective); CodeAssert.AreEqual(expected, editor.GetChangedDocument()); }
static async Task <Document> UseAsyncThrowsCheckAsync(Document document, InvocationExpressionSyntax invocation, MethodDeclarationSyntax method, string replacementMethod, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; var modifiers = GetModifiersWithAsyncKeywordAdded(method); var returnType = await GetReturnType(method, invocation, document, editor, cancellationToken).ConfigureAwait(false); var asyncThrowsInvocation = GetAsyncThrowsInvocation(invocation, replacementMethod, memberAccess); editor.ReplaceNode(method, method .ReplaceNode(invocation, asyncThrowsInvocation) .WithModifiers(modifiers) .WithReturnType(returnType)); return(editor.GetChangedDocument()); }
static async Task <Document> UseContainsCheckAsync(Document document, InvocationExpressionSyntax invocation, string replacementMethod, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; var invocationExpressionSyntax = (InvocationExpressionSyntax)invocation.ArgumentList.Arguments[0].Expression; var anyMethodInvocation = (MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression; var anyTarget = anyMethodInvocation.Expression; editor.ReplaceNode( invocation, invocation.WithArgumentList( SyntaxFactory.ArgumentList( SyntaxFactory.SeparatedList(invocationExpressionSyntax.ArgumentList.Arguments.Insert(0, SyntaxFactory.Argument(anyTarget))))) .WithExpression(memberAccess.WithName(SyntaxFactory.IdentifierName(replacementMethod)))); return(editor.GetChangedDocument()); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { DocumentEditor editor = await DocumentEditor.CreateAsync(context.Document, context.CancellationToken).ConfigureAwait(false); SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode node = root.FindNode(context.Span); SyntaxNode declaration = editor.Generator.GetDeclaration(node); if (declaration != null) { // We cannot have multiple overlapping diagnostics of this id. Diagnostic diagnostic = context.Diagnostics.Single(); context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.AvoidUnsealedAttributesMessage, async ct => await MakeSealed(editor, declaration, ct).ConfigureAwait(false)), diagnostic); } }
private static async Task <Document> ConvertToArrayEmpty(Document document, SyntaxNode nodeToFix, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = editor.SemanticModel; var generator = editor.Generator; var elementType = GetArrayElementType(nodeToFix, semanticModel, cancellationToken); if (elementType == null) { return(document); } var arrayEmptyInvocation = GenerateArrayEmptyInvocation(generator, elementType, semanticModel).WithTriviaFrom(nodeToFix); editor.ReplaceNode(nodeToFix, arrayEmptyInvocation); return(editor.GetChangedDocument()); }
private async Task <Document> AddUsingStatementAsync(CancellationToken cancelToken, Document document) { var editor = await DocumentEditor.CreateAsync(document, cancelToken); var syntaxRoot = await document.GetSyntaxRootAsync(); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; if (compilationUnit.Usings.Any(usDir => usDir.Name.GetText().ToString() == ShimsNamespace)) { return(document); } var usingStatement = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(ShimsNamespace)); var newCompilationUnit = compilationUnit.AddUsings(usingStatement); var modifiedDocument = document.WithSyntaxRoot(newCompilationUnit); return(modifiedDocument); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var token = context.CancellationToken; var semanticModel = await document.GetSemanticModelAsync(token).ConfigureAwait(false); _ = RequiredSymbols.TryGetSymbols(semanticModel.Compilation, out var symbols); RoslynDebug.Assert(symbols is not null); var root = await document.GetSyntaxRootAsync(token).ConfigureAwait(false); var node = root.FindNode(context.Span, getInnermostNodeForTie: true); if (semanticModel.GetOperation(node, token) is not IBinaryOperation violation) { return; } // Get the replacer that applies to the reported violation. var replacer = GetOperationReplacers(symbols).First(x => x.IsMatch(violation)); var codeAction = CodeAction.Create( Resx.UseStringEqualsOverStringCompareCodeFixTitle, CreateChangedDocument, nameof(Resx.UseStringEqualsOverStringCompareCodeFixTitle)); context.RegisterCodeFix(codeAction, context.Diagnostics); return; // Local functions async Task <Document> CreateChangedDocument(CancellationToken token) { var editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); var replacementNode = replacer.CreateReplacementExpression(violation, editor.Generator); editor.ReplaceNode(violation.Syntax, replacementNode); return(editor.GetChangedDocument()); } }
/// <summary> /// Forks the source document, keeps required type, namespace containers /// and adds it the solution. /// </summary> /// <param name="newDocumentId">id for the new document to be added</param> private async Task <Document> AddNewDocumentWithSingleTypeDeclarationAsync(DocumentId newDocumentId) { var document = SemanticDocument.Document; Debug.Assert(document.Name != FileName, $"New document name is same as old document name:{FileName}"); var root = SemanticDocument.Root; var projectToBeUpdated = document.Project; var documentEditor = await DocumentEditor.CreateAsync(document, CancellationToken).ConfigureAwait(false); // Make the type chain above this new type partial. Also, remove any // attributes from the containing partial types. We don't want to create // duplicate attributes on things. AddPartialModifiersToTypeChain( documentEditor, removeAttributesAndComments: true, removeTypeInheritance: true); // remove things that are not being moved, from the forked document. var membersToRemove = GetMembersToRemove(root); foreach (var member in membersToRemove) { documentEditor.RemoveNode(member, SyntaxRemoveOptions.KeepNoTrivia); } var modifiedRoot = documentEditor.GetChangedRoot(); modifiedRoot = await AddFinalNewLineIfDesiredAsync(document, modifiedRoot).ConfigureAwait(false); // add an empty document to solution, so that we'll have options from the right context. var solutionWithNewDocument = projectToBeUpdated.Solution.AddDocument( newDocumentId, FileName, text: string.Empty, folders: document.Folders); // update the text for the new document solutionWithNewDocument = solutionWithNewDocument.WithDocumentSyntaxRoot(newDocumentId, modifiedRoot, PreservationMode.PreserveIdentity); // get the updated document, give it the minimal set of imports that the type // inside it needs. var newDocument = solutionWithNewDocument.GetRequiredDocument(newDocumentId); return(newDocument); }
public static async Task BetweenInConditionalDirectives() { var code = @" namespace N { public class C { #if true public int P { get; } #endif #if true private int M() => 1; #endif } }"; var sln = CodeFactory.CreateSolution(code); var editor = await DocumentEditor.CreateAsync(sln.Projects.First().Documents.First()).ConfigureAwait(false); var containingType = editor.OriginalRoot.SyntaxTree.FindClassDeclaration("C"); var method = (MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("public int NewMethod() => 1;"); var expected = @" namespace N { public class C { #if true public int P { get; } #endif public int NewMethod() => 1; #if true private int M() => 1; #endif } }"; _ = editor.AddMethod(containingType, method); CodeAssert.AreEqual(expected, editor.GetChangedDocument()); }
private async Task <Document> CreateChangedDocument( CodeFixContext context, TArgumentListSyntax argumentListSyntax, IReadOnlyList <TArgumentSyntax> argumentSyntaxes, CancellationToken ct) { var documentEditor = await DocumentEditor.CreateAsync(context.Document, ct); var semanticModel = await context.Document.GetSemanticModelAsync(ct); var invocationSyntaxNode = argumentListSyntax.Parent; if (!(semanticModel.GetSymbolInfo(invocationSyntaxNode).Symbol is IMethodSymbol methodSymbol)) { return(context.Document); } var skip = methodSymbol.MethodKind == MethodKind.Ordinary ? 1 : 0; foreach (var argumentSyntax in argumentSyntaxes.Skip(skip)) { if (IsArrayParamsArgument(semanticModel, argumentSyntax)) { var updatedParamsArgumentSyntaxNode = CreateUpdatedParamsArgumentSyntaxNode( SyntaxGenerator.GetGenerator(context.Document), methodSymbol.TypeArguments.FirstOrDefault() ?? methodSymbol.ReceiverType, argumentSyntax); documentEditor.ReplaceNode(argumentSyntax, updatedParamsArgumentSyntaxNode); } else { var updatedArgumentSyntax = CreateUpdatedArgumentSyntaxNode(argumentSyntax); documentEditor.ReplaceNode(argumentSyntax, updatedArgumentSyntax); } } return(await Simplifier.ReduceAsync(documentEditor.GetChangedDocument(), cancellationToken : ct)); }
public static async Task AddInternalAndPrivateWhenPublicAndPrivateExists() { var code = @" namespace N { class C { /// <summary> F1 </summary> public static readonly int F1; /// <summary> f3 </summary> private static readonly int f3; } }"; var sln = CodeFactory.CreateSolution(code); var editor = await DocumentEditor.CreateAsync(sln.Projects.First().Documents.First()).ConfigureAwait(false); var containingType = editor.OriginalRoot.SyntaxTree.FindClassDeclaration("C"); var expected = @" namespace N { class C { /// <summary> F1 </summary> public static readonly int F1; private static readonly int f2; /// <summary> F2 </summary> internal static readonly int F2 = f2; /// <summary> f3 </summary> private static readonly int f3; } }"; _ = editor.AddField(containingType, (FieldDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(@"/// <summary> F2 </summary> internal static readonly int F2 = f2;")) .AddField(containingType, (FieldDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("private static readonly int f2;")); CodeAssert.AreEqual(expected, editor.GetChangedDocument()); }
private static async Task TestAsync(string initialText, string attributeAddedText) { var doc = GetDocument(initialText); var options = await doc.GetOptionsAsync(); var attributeList = SyntaxFactory .AttributeList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Attribute( SyntaxFactory.IdentifierName( "System.Reflection.AssemblyVersion(\"1.0.0.0\")" ) ) ) ) .WithTarget( SyntaxFactory.AttributeTargetSpecifier( SyntaxFactory.Token(SyntaxKind.AssemblyKeyword) ) ); var syntaxRoot = await doc.GetSyntaxRootAsync(); var editor = await DocumentEditor.CreateAsync(doc); editor.AddAttribute(syntaxRoot, attributeList); var changedDoc = editor.GetChangedDocument(); if (attributeAddedText != null) { var formatted = await Formatter.FormatAsync( changedDoc, SyntaxAnnotation.ElasticAnnotation, options ); var actualText = (await formatted.GetTextAsync()).ToString(); Assert.Equal(attributeAddedText, actualText); } }
private async Task <Document> ImplementMissingMembersAsync( SyntaxNode declaration, INamedTypeSymbol typeSymbol, Document document, CancellationToken ct) { var editor = await DocumentEditor.CreateAsync(document, ct).ConfigureAwait(false); var generator = editor.Generator; if (!typeSymbol.OverridesEquals()) { var equalsMethod = generator.DefaultEqualsOverrideDeclaration( editor.SemanticModel.Compilation, typeSymbol); editor.AddMember(declaration, equalsMethod); } if (!typeSymbol.OverridesGetHashCode()) { var getHashCodeMethod = generator.DefaultGetHashCodeOverrideDeclaration( editor.SemanticModel.Compilation); editor.AddMember(declaration, getHashCodeMethod); } if (!typeSymbol.ImplementsOperator(WellKnownMemberNames.EqualityOperatorName)) { var equalityOperator = generator.DefaultOperatorEqualityDeclaration(typeSymbol); editor.AddMember(declaration, equalityOperator); } if (!typeSymbol.ImplementsOperator(WellKnownMemberNames.InequalityOperatorName)) { var inequalityOperator = generator.DefaultOperatorInequalityDeclaration(typeSymbol); editor.AddMember(declaration, inequalityOperator); } return(editor.GetChangedDocument()); }
public async Task <Solution> InlineAndRemoveMethodAsync( ExpressionStatementSyntax expressionStatement, SyntaxList <StatementSyntax> statements) { if (expressionStatement.SyntaxTree == MethodDeclaration.SyntaxTree) { DocumentEditor editor = await DocumentEditor.CreateAsync(Document, CancellationToken).ConfigureAwait(false); StatementSyntax[] newStatements = RewriteStatements(statements); int count = statements.Count; newStatements[0] = newStatements[0].WithLeadingTrivia(expressionStatement.GetLeadingTrivia()); newStatements[count - 1] = newStatements[count - 1].WithTrailingTrivia(expressionStatement.GetTrailingTrivia()); StatementContainer container; if (StatementContainer.TryCreate(expressionStatement, out container)) { SyntaxNode newNode = container.NodeWithStatements(container.Statements.ReplaceRange(expressionStatement, newStatements)); editor.ReplaceNode(container.Node, newNode); } else { editor.ReplaceNode(expressionStatement, Block(newStatements)); } editor.RemoveNode(MethodDeclaration); return(editor.GetChangedDocument().Solution()); } else { Document newDocument = await InlineMethodAsync(expressionStatement, statements).ConfigureAwait(false); DocumentId documentId = Document.Solution().GetDocumentId(MethodDeclaration.SyntaxTree); newDocument = await newDocument.Solution().GetDocument(documentId).RemoveMemberAsync(MethodDeclaration, CancellationToken).ConfigureAwait(false); return(newDocument.Solution()); } }
private async Task <Solution> HoistAssignment(Document document, InvocationExpressionSyntax paramsInvocation, CancellationToken cancellationToken) { var originalSolution = document.Project.Solution; var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var method = semanticModel.GetSymbolInfo(paramsInvocation).Symbol as IMethodSymbol; var typeDisplayString = method.Parameters.Last().Type.ToMinimalDisplayString(semanticModel, method.Parameters.Last().Locations.First().SourceSpan.Start); var bracketedSyntax = SyntaxFactory.BracketedArgumentList(); var updatedParameters = new SeparatedSyntaxList <ExpressionSyntax>(); var actualArguments = paramsInvocation.ArgumentList.Arguments.Skip(method.Parameters.Length - 1).Select(x => x.Expression).ToArray(); updatedParameters = updatedParameters.AddRange(actualArguments); var newArray = SyntaxFactory.InitializerExpression(SyntaxKind.ArrayInitializerExpression, updatedParameters); var typeSyntax = SyntaxFactory.ParseTypeName(typeDisplayString); var objectCreationExpression = SyntaxFactory.ObjectCreationExpression(typeSyntax, null, newArray).WithAdditionalAnnotations(Formatter.Annotation); var equalsValueClause = SyntaxFactory.EqualsValueClause(objectCreationExpression); var declarator = new SeparatedSyntaxList <VariableDeclaratorSyntax>(); declarator = declarator.Add(SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier("hoisted"), null, equalsValueClause)); var variableAssignment = SyntaxFactory.VariableDeclaration(typeSyntax, declarator).WithAdditionalAnnotations(Formatter.Annotation); var assignmentExpression = SyntaxFactory.LocalDeclarationStatement(variableAssignment); var forStatement = IsInSyntax <ForStatementSyntax>(paramsInvocation); var invocationParameterReplacement = new SeparatedSyntaxList <ArgumentSyntax>(); invocationParameterReplacement = invocationParameterReplacement.AddRange(paramsInvocation.ArgumentList.Arguments.Take(method.Parameters.Length - 1)); invocationParameterReplacement = invocationParameterReplacement.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName("hoisted"))); var newArgListSyntax = SyntaxFactory.ArgumentList(invocationParameterReplacement); var newDeclaration = paramsInvocation.WithArgumentList(newArgListSyntax); var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); documentEditor.InsertBefore(forStatement, assignmentExpression); documentEditor.ReplaceNode(paramsInvocation, newDeclaration); var newDocument = documentEditor.GetChangedDocument(); var finalRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); finalRoot = Formatter.Format(finalRoot, Formatter.Annotation, document.Project.Solution.Workspace); return(originalSolution.WithDocumentSyntaxRoot(document.Id, finalRoot)); }
private async Task <Solution> RemoveNodes(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var solution = document.Project.Solution; var pairs = await GetNodesToRemoveAsync(document, diagnostic, cancellationToken).ConfigureAwait(false); foreach (var group in pairs.GroupBy(p => p.Key)) { DocumentEditor editor = await DocumentEditor.CreateAsync(solution.GetDocument(group.Key), cancellationToken).ConfigureAwait(false); // Start removing from bottom to top to keep spans of nodes that are removed later. foreach (var value in group.OrderByDescending(v => v.Value.SpanStart)) { editor.RemoveNode(value.Value); } solution = solution.WithDocumentSyntaxRoot(group.Key, editor.GetChangedRoot()); } return(solution); }
public static async Task StringBuilderType() { var code = @" namespace N { }"; var sln = CodeFactory.CreateSolution(code); var document = sln.Projects.First().Documents.First(); var editor = await DocumentEditor.CreateAsync(document).ConfigureAwait(false); var expected = @" namespace N { using System.Text; }"; var type = editor.SemanticModel.Compilation.ObjectType.ContainingAssembly.GetTypeByMetadataName("System.Text.StringBuilder"); _ = editor.AddUsing(type); CodeAssert.AreEqual(expected, editor.GetChangedDocument()); }
private static async Task <Document> PrefixWithUsingDeclaration(CodeFixContext context, CancellationToken cancel) { var oldRoot = await context.Document.GetSyntaxRootAsync(cancel); if (!(oldRoot.FindNode(context.Span) is ExpressionSyntax node)) { return(context.Document); } if (!node.TryFindParent <LocalDeclarationStatementSyntax>(out var localDeclaration)) { return(context.Document); } var newLocalDeclaration = localDeclaration.WithUsingKeyword(Token(SyntaxKind.UsingKeyword)); var editor = await DocumentEditor.CreateAsync(context.Document, context.CancellationToken); editor.ReplaceNode(localDeclaration, newLocalDeclaration); return(editor.GetChangedDocument()); }