Example #1
0
        private static Fix CreateFix(
            SyntaxGenerator syntaxGenerator,
            PropertyDeclarationSyntax propertyDeclaration,
            IPropertySymbol property,
            IMethodSymbol invoker,
            SemanticModel semanticModel,
            CancellationToken cancellationToken,
            ImmutableDictionary <string, ReportDiagnostic> diagnosticOptions)
        {
            string backingFieldName;

            if (Property.IsMutableAutoProperty(propertyDeclaration))
            {
                backingFieldName = MakePropertyNotifyHelper.BackingFieldNameForAutoProperty(propertyDeclaration);
                var backingField = (FieldDeclarationSyntax)syntaxGenerator.FieldDeclaration(
                    backingFieldName,
                    propertyDeclaration.Type,
                    Accessibility.Private,
                    DeclarationModifiers.None);
                var notifyingProperty = propertyDeclaration.WithGetterReturningBackingField(
                    syntaxGenerator,
                    backingFieldName)
                                        .WithNotifyingSetter(
                    property,
                    syntaxGenerator,
                    backingFieldName,
                    invoker,
                    diagnosticOptions);
                return(new Fix(propertyDeclaration, notifyingProperty, backingField));
            }

            if (IsSimpleAssignmentOnly(
                    propertyDeclaration,
                    semanticModel,
                    cancellationToken,
                    out ExpressionStatementSyntax assignStatement,
                    out backingFieldName))
            {
                var notifyingProperty = propertyDeclaration.WithGetterReturningBackingField(
                    syntaxGenerator,
                    backingFieldName)
                                        .WithNotifyingSetter(
                    property,
                    syntaxGenerator,
                    assignStatement,
                    backingFieldName,
                    invoker,
                    diagnosticOptions);
                return(new Fix(propertyDeclaration, notifyingProperty, null));
            }

            return(new Fix(propertyDeclaration, null, null));
        }
        /// <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.TryGetBackingField(property, semanticModel, context.CancellationToken, out IFieldSymbol backingField))
                {
                    continue;
                }

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

                    var referenceTypeEquality = MakePropertyNotifyHelper.ReferenceTypeEquality(context.Document.Project.CompilationOptions.SpecificDiagnosticOptions);
                    var equalsExpression      = (ExpressionSyntax)syntaxGenerator.InvocationExpression(
                        referenceTypeEquality,
                        SyntaxFactory.ParseName("value"),
                        SyntaxFactory.ParseExpression(fieldAccess));

                    context.RegisterCodeFix(
                        CodeAction.Create(
                            $"Use {referenceTypeEquality}",
                            cancellationToken => Task.FromResult(context.Document.WithSyntaxRoot(syntaxRoot.ReplaceNode(ifStatement.Condition, equalsExpression))),
                            this.GetType().FullName),
                        diagnostic);
                }
            }
        }