예제 #1
0
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken)
                                .ConfigureAwait(false);

            foreach (var diagnostic in context.Diagnostics)
            {
                var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start);
                if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing)
                {
                    continue;
                }

                var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
                if (node is ObjectCreationExpressionSyntax objectCreation)
                {
                    var type = (ITypeSymbol)semanticModel.GetSymbolSafe(objectCreation, context.CancellationToken)?.ContainingSymbol;
                    if (type == null)
                    {
                        continue;
                    }

                    var parameterSyntax = SyntaxFactory.Parameter(SyntaxFactory.Identifier(ParameterName(type)))
                                          .WithType(objectCreation.Type);
                    switch (GU0007PreferInjecting.CanInject(objectCreation, semanticModel, context.CancellationToken))
                    {
                    case GU0007PreferInjecting.Injectable.No:
                        continue;

                    case GU0007PreferInjecting.Injectable.Safe:
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                "Inject",
                                cancellationToken => ApplyFixAsync(context, semanticModel, cancellationToken, objectCreation, parameterSyntax),
                                nameof(InjectFix)),
                            diagnostic);
                        break;

                    case GU0007PreferInjecting.Injectable.Unsafe:
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                "Inject UNSAFE",
                                cancellationToken => ApplyFixAsync(context, semanticModel, cancellationToken, objectCreation, parameterSyntax),
                                nameof(InjectFix)),
                            diagnostic);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                if (node is IdentifierNameSyntax identifierName &&
                    identifierName.Parent is MemberAccessExpressionSyntax memberAccess)
                {
                    var type            = GU0007PreferInjecting.MemberType(memberAccess, semanticModel, context.CancellationToken);
                    var parameterSyntax = SyntaxFactory.Parameter(SyntaxFactory.Identifier(ParameterName(type)))
                                          .WithType(SyntaxFactory.ParseTypeName(type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)));
                    switch (GU0007PreferInjecting.IsInjectable(identifierName, semanticModel, context.CancellationToken))
                    {
                    case GU0007PreferInjecting.Injectable.No:
                        continue;

                    case GU0007PreferInjecting.Injectable.Safe:
                    case GU0007PreferInjecting.Injectable.Unsafe:
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                "Inject UNSAFE",
                                cancellationToken => ApplyFixAsync(context, semanticModel, cancellationToken, identifierName, parameterSyntax),
                                nameof(InjectFix)),
                            diagnostic);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
        }
예제 #2
0
        private static async Task <Document> ApplyFixAsync(CodeFixContext context, SemanticModel semanticModel, CancellationToken cancellationToken, ExpressionSyntax expression, ParameterSyntax parameterSyntax)
        {
            if (GU0007PreferInjecting.TrySingleConstructor(expression, out var ctor))
            {
                var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken)
                             .ConfigureAwait(false);

                parameterSyntax = UniqueName(ctor.ParameterList, parameterSyntax);
                if (expression is ObjectCreationExpressionSyntax)
                {
                    editor.ReplaceNode(expression, SyntaxFactory.IdentifierName(parameterSyntax.Identifier));
                }
                else if (expression is IdentifierNameSyntax identifierName &&
                         expression.Parent is MemberAccessExpressionSyntax)
                {
                    var replaceNodes = new ReplaceNodes(identifierName, semanticModel, cancellationToken).Nodes;
                    if (replaceNodes.Count == 0)
                    {
                        return(context.Document);
                    }

                    ExpressionSyntax fieldAccess = null;
                    foreach (var replaceNode in replaceNodes)
                    {
                        if (replaceNode.FirstAncestor <ConstructorDeclarationSyntax>() == null)
                        {
                            if (fieldAccess == null)
                            {
                                fieldAccess = WithField(editor, ctor, parameterSyntax);
                            }

                            editor.ReplaceNode(replaceNode, fieldAccess.WithLeadingTrivia(replaceNode.GetLeadingTrivia()));
                        }
                        else
                        {
                            editor.ReplaceNode(replaceNode, SyntaxFactory.IdentifierName(parameterSyntax.Identifier).WithLeadingTrivia(replaceNode.GetLeadingTrivia()));
                        }
                    }
                }
                else
                {
                    return(context.Document);
                }

                if (ctor.ParameterList == null)
                {
                    editor.ReplaceNode(ctor, ctor.WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(parameterSyntax))));
                }
                else
                {
                    if (ctor.ParameterList.Parameters.TryFirst(p => p.Default != null || p.Modifiers.Any(SyntaxKind.ParamsKeyword), out var existing))
                    {
                        editor.InsertBefore(existing, parameterSyntax);
                    }
                    else
                    {
                        editor.ReplaceNode(ctor.ParameterList, ctor.ParameterList.AddParameters(parameterSyntax));
                    }
                }

                return(editor.GetChangedDocument());
            }