示例#1
0
        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());
        }
示例#3
0
        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());
        }
示例#4
0
        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());
        }
示例#6
0
    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("}")));
        }
    }
示例#7
0
        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);
        }
示例#8
0
        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));
            }
        }
示例#9
0
            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());
        }
示例#11
0
        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());
        }
示例#12
0
        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());
        }
示例#15
0
        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);
            }
        }
示例#17
0
        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);
            }
示例#21
0
        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));
        }
示例#23
0
        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());
        }
示例#24
0
        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());
        }
示例#26
0
        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());
            }
        }
示例#27
0
        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));
        }
示例#28
0
        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);
        }
示例#29
0
        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());
        }