Esempio n. 1
0
        private static void MakeWithBackingFieldNotify(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>();

            if (classDeclaration == null)
            {
                return;
            }

            if (IsSimpleAssignmentOnly(propertyDeclaration, out var setter, out var statement, out var assignment, out _))
            {
                var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                var property         = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                var notifyStatement  = SyntaxFactory
                                       .ParseStatement(Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields))
                                       .WithLeadingTrivia(SyntaxFactory.ElasticMarker)
                                       .WithTrailingTrivia(SyntaxFactory.ElasticMarker)
                                       .WithSimplifiedNames()
                                       .WithAdditionalAnnotations(Formatter.Annotation);
                if (setter.ExpressionBody != null)
                {
                    editor.ReplaceNode(
                        setter,
                        (x, _) =>
                    {
                        var old = (AccessorDeclarationSyntax)x;
                        return(old.WithBody(
                                   SyntaxFactory.Block(
                                       SyntaxFactory.ExpressionStatement(assignment),
                                       notifyStatement))
                               .WithExpressionBody(null)
                               .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)));
                    });
                    editor.FormatNode(propertyDeclaration);
                }
                else if (setter.Body != null)
                {
                    editor.InsertAfter(statement, notifyStatement);
                    editor.FormatNode(propertyDeclaration);
                }
            }
        }
Esempio n. 2
0
        private static void MakeNotify(DocumentEditor editor, ExpressionSyntax assignment, string propertyName, IMethodSymbol invoker, bool usesUnderscoreNames)
        {
            var snippet =
                assignment.FirstAncestor <PropertyDeclarationSyntax>() is PropertyDeclarationSyntax
                propertyDeclaration &&
                propertyDeclaration.Identifier.ValueText == propertyName
                    ? Snippet.OnPropertyChanged(invoker, propertyName, usesUnderscoreNames)
                    : Snippet.OnOtherPropertyChanged(invoker, propertyName, usesUnderscoreNames);

            var onPropertyChanged = SyntaxFactory.ParseStatement(snippet)
                                    .WithSimplifiedNames()
                                    .WithLeadingElasticLineFeed()
                                    .WithTrailingElasticLineFeed()
                                    .WithAdditionalAnnotations(Formatter.Annotation);

            if (assignment.Parent is AnonymousFunctionExpressionSyntax anonymousFunction)
            {
                if (anonymousFunction.Body is BlockSyntax block)
                {
                    if (block.Statements.Count > 1)
                    {
                        var previousStatement = InsertAfter(block, block.Statements.Last(), invoker);
                        editor.InsertAfter(previousStatement, new[] { onPropertyChanged });
                    }

                    return;
                }

                var expressionStatement = (ExpressionStatementSyntax)editor.Generator.ExpressionStatement(anonymousFunction.Body);
                var withStatements      = editor.Generator.WithStatements(anonymousFunction, new[] { expressionStatement, onPropertyChanged });
                editor.ReplaceNode(anonymousFunction, withStatements);
            }
            else if (assignment.Parent is ExpressionStatementSyntax assignStatement &&
                     assignStatement.Parent is BlockSyntax assignBlock)
            {
                var previousStatement = InsertAfter(assignBlock, assignStatement, invoker);
                editor.InsertAfter(previousStatement, new[] { onPropertyChanged });
            }
Esempio n. 3
0
        private static void MakeWithBackingFieldNotifyWhenValueChanges(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>();

            if (classDeclaration == null)
            {
                return;
            }

            if (propertyDeclaration.TryGetSetter(out var setter))
            {
                if (setter.ExpressionBody != null &&
                    IsSimpleAssignmentOnly(propertyDeclaration, out _, out _, out var assignment, out _))
                {
                    var property         = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                    var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                    var code             = StringBuilderPool.Borrow()
                                           .AppendLine($"public Type PropertyName")
                                           .AppendLine("{")
                                           .AppendLine($"    get => {assignment.Left};")
                                           .AppendLine()
                                           .AppendLine("    set")
                                           .AppendLine("    {")
                                           .AppendLine($"        if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})")
                                           .AppendLine("        {")
                                           .AppendLine($"           return;")
                                           .AppendLine("        }")
                                           .AppendLine()
                                           .AppendLine($"        {assignment};")
                                           .AppendLine($"        {Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)}")
                                           .AppendLine("    }")
                                           .AppendLine("}")
                                           .Return();
                    var template = ParseProperty(code);
                    editor.ReplaceNode(
                        setter,
                        (x, _) =>
                    {
                        var old = (AccessorDeclarationSyntax)x;
                        return(old.WithBody(template.Setter().Body)
                               .WithExpressionBody(null)
                               .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)));
                    });
                    editor.FormatNode(propertyDeclaration);
                }

                if (setter.Body?.Statements.Count == 1 &&
                    IsSimpleAssignmentOnly(propertyDeclaration, out _, out var statement, out assignment, out _))
                {
                    var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                    var code     = StringBuilderPool.Borrow()
                                   .AppendLine($"        if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})")
                                   .AppendLine("        {")
                                   .AppendLine($"           return;")
                                   .AppendLine("        }")
                                   .AppendLine()
                                   .Return();
                    var ifStatement = SyntaxFactory.ParseStatement(code)
                                      .WithSimplifiedNames()
                                      .WithLeadingElasticLineFeed()
                                      .WithTrailingElasticLineFeed()
                                      .WithAdditionalAnnotations(Formatter.Annotation);
                    editor.InsertBefore(
                        statement,
                        ifStatement);
                    var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                    var notifyStatement  = SyntaxFactory
                                           .ParseStatement(
                        Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields))
                                           .WithSimplifiedNames()
                                           .WithLeadingElasticLineFeed()
                                           .WithTrailingElasticLineFeed()
                                           .WithAdditionalAnnotations(Formatter.Annotation);
                    editor.InsertAfter(statement, notifyStatement);
                    editor.FormatNode(propertyDeclaration);
                }
            }
        }
Esempio n. 4
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))
                {
                    continue;
                }

                var ifStatement = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                  .FirstAncestorOrSelf <IfStatementSyntax>();
                if (!IsIfReturn(ifStatement))
                {
                    continue;
                }

                var setter = ifStatement.FirstAncestorOrSelf <AccessorDeclarationSyntax>();
                if (setter?.IsKind(SyntaxKind.SetAccessorDeclaration) != true)
                {
                    continue;
                }

                var propertyDeclaration = setter.FirstAncestorOrSelf <PropertyDeclarationSyntax>();
                var property            = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, context.CancellationToken);

                if (property == null)
                {
                    continue;
                }

                if (!Property.TryGetBackingFieldFromSetter(property, semanticModel, context.CancellationToken, out var backingField))
                {
                    continue;
                }

                if (Property.TryFindValue(setter, semanticModel, context.CancellationToken, out var value))
                {
                    if (CanFix(ifStatement, semanticModel, context.CancellationToken, value, backingField) ||
                        CanFix(ifStatement, semanticModel, context.CancellationToken, value, property))
                    {
                        var fieldAccess = backingField.Name.StartsWith("_")
                            ? backingField.Name
                            : $"this.{backingField.Name}";

                        var equalsExpression = SyntaxFactory.ParseExpression(
                            Snippet.EqualityCheck(
                                property.Type,
                                "value",
                                fieldAccess,
                                semanticModel))
                                               .WithSimplifiedNames();

                        context.RegisterDocumentEditorFix(
                            $"Use {equalsExpression}",
                            (editor, cancellationToken) => editor.ReplaceNode(ifStatement.Condition, equalsExpression),
                            this.GetType(),
                            diagnostic);
                    }
                }
            }
        }