/// <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)
            {
                if (syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                    .TryFirstAncestorOrSelf <ExpressionStatementSyntax>(out var statement))
                {
                    if (TryGetField(statement, semanticModel, context.CancellationToken, out var field))
                    {
                        context.RegisterDocumentEditorFix(
                            "Add to CompositeDisposable.",
                            (editor, cancellationToken) => AddToExisting(editor, statement, field),
                            diagnostic);
                    }
                    else
                    {
                        if (semanticModel.Compilation.ReferencedAssemblyNames.Any(x => x.Name.Contains("System.Reactive")))
                        {
                            context.RegisterDocumentEditorFix(
                                "Add to new CompositeDisposable.",
                                (editor, cancellationToken) =>
                                CreateAndInitialize(editor, statement, cancellationToken),
                                diagnostic);
                        }
                    }
                }
            }
        }
        /// <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)
            {
                if (syntaxRoot.TryFindNode <MemberDeclarationSyntax>(diagnostic, out var member) &&
                    semanticModel.TryGetSymbol(member, context.CancellationToken, out ISymbol memberSymbol))
                {
                    if (DisposeMethod.TryFindVirtualDispose(memberSymbol.ContainingType, semanticModel.Compilation, Search.TopLevel, out var disposeMethod) &&
                        disposeMethod.TrySingleDeclaration(context.CancellationToken, out MethodDeclarationSyntax disposeMethodDeclaration))
                    {
                        context.RegisterDocumentEditorFix(
                            "Dispose member.",
                            (editor, cancellationToken) => DisposeInVirtualDisposeMethod(editor, memberSymbol, disposeMethodDeclaration, cancellationToken),
                            diagnostic);
                    }
                    else if (DisposeMethod.TryFindIDisposableDispose(memberSymbol.ContainingType, semanticModel.Compilation, Search.TopLevel, out disposeMethod) &&
                             disposeMethod.TrySingleDeclaration(context.CancellationToken, out disposeMethodDeclaration))
                    {
                        context.RegisterDocumentEditorFix(
                            "Dispose member.",
                            (editor, cancellationToken) => DisposeInDisposeMethod(editor, memberSymbol, disposeMethodDeclaration, cancellationToken),
                            diagnostic);
                    }
                }
            }
        }
        /// <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 syntaxNode = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (diagnostic.Id == GU0021CalculatedPropertyAllocates.DiagnosticId)
                {
                    var objectCreation = GetObjectCreation(syntaxNode);
                    if (objectCreation != null)
                    {
                        var arguments  = objectCreation.ArgumentList.Arguments;
                        var hasMutable = IsAnyArgumentMutable(semanticModel, context.CancellationToken, arguments) ||
                                         IsAnyInitializerMutable(semanticModel, context.CancellationToken, objectCreation.Initializer);

                        var property = syntaxNode.FirstAncestorOrSelf <PropertyDeclarationSyntax>();
                        if (TryGetConstructor(property, out ConstructorDeclarationSyntax ctor))
                        {
                            context.RegisterDocumentEditorFix(
                                "Use get-only" + (hasMutable ? " UNSAFE" : string.Empty),
                                (editor, cancellationToken) => ApplyInitializeInCtorFix(editor, ctor, property, objectCreation, cancellationToken),
                                this.GetType().FullName + "UNSAFE",
                                diagnostic);
                        }
                    }
                }
                else if (diagnostic.Id == GU0022UseGetOnly.DiagnosticId)
                {
                    var setter = syntaxNode.FirstAncestorOrSelf <AccessorDeclarationSyntax>();
                    if (setter != null)
                    {
                        context.RegisterDocumentEditorFix(
                            "Use get-only",
                            (editor, _) => ApplyRemoveSetterFix(editor, setter),
                            this.GetType(),
                            diagnostic);
                    }
                }
            }
        }
Example #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);

            var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);

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

                var argument = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                               .FirstAncestorOrSelf <ArgumentSyntax>();
                var type = semanticModel.GetDeclaredSymbolSafe(argument?.FirstAncestorOrSelf <ClassDeclarationSyntax>(), context.CancellationToken);
                if (PropertyChanged.TryGetOnPropertyChanged(type, semanticModel, context.CancellationToken, out var invoker))
                {
                    context.RegisterDocumentEditorFix(
                        "Use overload that does not use expression.",
                        (editor, cancellationToken) => RemoveExpression(editor, argument, invoker, underscoreFields, cancellationToken),
                        this.GetType(),
                        diagnostic);
                }
            }
        }
        /// <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 node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (node is AssignmentExpressionSyntax assignment &&
                    Property.TryGetAssignedProperty(assignment, out var propertyDeclaration) &&
                    Property.TryGetBackingFieldFromSetter(propertyDeclaration, semanticModel, context.CancellationToken, out var field))
                {
                    context.RegisterDocumentEditorFix(
                        "Set backing field.",
                        (e, cancellationToken) => SetBackingField(e, assignment, field),
                        diagnostic);
                }
            }
        }
Example #6
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 arguments = (ArgumentListSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (HasAnyNamedArgument(arguments))
                {
                    continue;
                }

                var method = semanticModel.GetSymbolSafe(arguments.Parent, context.CancellationToken) as IMethodSymbol;
                if (method == null)
                {
                    continue;
                }

                context.RegisterDocumentEditorFix(
                    "Name arguments",
                    (editor, _) => ApplyFix(editor, method, arguments),
                    this.GetType(),
                    diagnostic);
            }
        }
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(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;
                }

                if (diagnostic.Id == GU0002NamedArgumentPositionMatches.DiagnosticId)
                {
                    var arguments = (ArgumentListSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                    if (!HasWhitespaceTriviaOnly(arguments))
                    {
                        continue;
                    }

                    context.RegisterDocumentEditorFix(
                        "Move arguments to match parameter positions.",
                        (editor, cancellationToken) => ApplyFixGU0002(editor, arguments, cancellationToken),
                        this.GetType(),
                        diagnostic);
                }

                if (diagnostic.Id == GU0005ExceptionArgumentsPositions.DiagnosticId)
                {
                    var argument = (ArgumentSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                    context.RegisterDocumentEditorFix(
                        "Move name argument to match parameter positions.",
                        (editor, cancellationToken) => ApplyFixGU0005(editor, argument, cancellationToken),
                        this.GetType(),
                        diagnostic);
                }
            }
        }
        /// <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 node   = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                var member = node as MemberDeclarationSyntax ??
                             (SyntaxNode)(node as AssignmentExpressionSyntax)?.Left;
                if (semanticModel.TryGetSymbol(member, context.CancellationToken, out ISymbol memberSymbol) &&
                    FieldOrProperty.TryCreate(memberSymbol, out var fieldOrProperty) &&
                    TestFixture.IsAssignedInSetUp(fieldOrProperty, member.FirstAncestor <ClassDeclarationSyntax>(), semanticModel, context.CancellationToken, out var setupAttribute))
                {
                    if (TestFixture.TryGetTearDownMethod(setupAttribute, semanticModel, context.CancellationToken, out var tearDownMethodDeclaration))
                    {
                        context.RegisterDocumentEditorFix(
                            $"Dispose member in {tearDownMethodDeclaration.Identifier.ValueText}.",
                            (editor, cancellationToken) => DisposeInTearDownMethod(editor, memberSymbol, tearDownMethodDeclaration, cancellationToken),
                            diagnostic);
                    }
                    else if (setupAttribute.TryFirstAncestor <MethodDeclarationSyntax>(out var setupMethod))
                    {
                        var tearDownType = semanticModel.GetTypeInfoSafe(setupAttribute, context.CancellationToken)
                                           .Type == KnownSymbol.NUnitSetUpAttribute
                            ? KnownSymbol.NUnitTearDownAttribute
                            : KnownSymbol.NUnitOneTimeTearDownAttribute;

                        context.RegisterDocumentEditorFix(
                            $"Create {tearDownType.Type} method and dispose member.",
                            (editor, cancellationToken) => CreateTearDownMethod(editor, memberSymbol, setupMethod, tearDownType, cancellationToken),
                            diagnostic);
                    }
                }
            }
        }
Example #9
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 node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (diagnostic.Id == IDISP001DisposeCreated.DiagnosticId &&
                    node.TryFirstAncestorOrSelf <LocalDeclarationStatementSyntax>(out var localDeclaration) &&
                    localDeclaration.TryFirstAncestor <ConstructorDeclarationSyntax>(out _) &&
                    localDeclaration.Declaration.Variables.TrySingle(out var variable) &&
                    variable.Initializer != null &&
                    semanticModel.TryGetType(localDeclaration.Declaration.Type, context.CancellationToken, out var type))
                {
                    context.RegisterDocumentEditorFix(
                        "Create and assign field.",
                        (editor, cancellationToken) => CreateAndAssignField(editor, localDeclaration, type),
                        diagnostic);
                }
Example #10
0
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            if (syntaxRoot == null)
            {
                return;
            }

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

            foreach (var diagnostic in context.Diagnostics)
            {
                var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (node is AssignmentExpressionSyntax assignment &&
                    TryCreateDisposeStatement(assignment, semanticModel, context.CancellationToken, out var disposeStatement))
                {
                    context.RegisterDocumentEditorFix(
                        "Dispose before re-assigning.",
                        (editor, cancellationToken) => ApplyDisposeBeforeAssign(editor, assignment, disposeStatement),
                        diagnostic);
                }
Example #11
0
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(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 argument = (ArgumentSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (argument.Expression is LiteralExpressionSyntax literal)
                {
                    context.RegisterDocumentEditorFix(
                        "Use nameof",
                        (editor, cancellationToken) => ApplyFix(editor, argument, literal.Token.ValueText, cancellationToken),
                        this.GetType(),
                        diagnostic);
                }
            }
        }
Example #12
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 propertyDeclaration    = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <PropertyDeclarationSyntax>();
                var classDeclarationSyntax = propertyDeclaration?.Parent as ClassDeclarationSyntax;
                if (classDeclarationSyntax == null)
                {
                    continue;
                }

                var type = semanticModel.GetDeclaredSymbolSafe(classDeclarationSyntax, context.CancellationToken);
                if (PropertyChanged.TryGetSetAndRaise(type, semanticModel, context.CancellationToken, out var setAndRaiseMethod))
                {
                    var key = $"{setAndRaiseMethod.ContainingType.MetadataName}.{setAndRaiseMethod.MetadataName}.";
                    if (Property.IsMutableAutoProperty(propertyDeclaration, out _, out _))
                    {
                        context.RegisterDocumentEditorFix(
                            key,
                            (editor, cancellationToken) => MakeAutoPropertySet(
                                editor,
                                propertyDeclaration,
                                setAndRaiseMethod,
                                semanticModel,
                                cancellationToken),
                            key,
                            diagnostic);
                    }
                    else if (IsSimpleAssignmentOnly(propertyDeclaration, out _, out _, out _, out _))
                    {
                        context.RegisterDocumentEditorFix(
                            key,
                            (editor, cancellationToken) => MakeWithBackingFieldSet(
                                editor,
                                propertyDeclaration,
                                setAndRaiseMethod,
                                semanticModel),
                            key,
                            diagnostic);
                    }
                }

                if (PropertyChanged.TryGetOnPropertyChanged(type, semanticModel, context.CancellationToken, out var invoker) &&
                    invoker.Parameters.Length == 1)
                {
                    if (invoker.Parameters[0].Type == KnownSymbol.String ||
                        invoker.Parameters[0].Type == KnownSymbol.PropertyChangedEventArgs)
                    {
                        if (Property.IsMutableAutoProperty(propertyDeclaration, out _, out _))
                        {
                            context.RegisterDocumentEditorFix(
                                NotifyWhenValueChanges,
                                (editor, cancellationToken) => MakeAutoPropertyNotifyWhenValueChanges(editor, propertyDeclaration, invoker, semanticModel, cancellationToken),
                                NotifyWhenValueChanges,
                                diagnostic);
                        }
                        else if (IsSimpleAssignmentOnly(propertyDeclaration, out _, out _, out _, out _))
                        {
                            context.RegisterDocumentEditorFix(
                                NotifyWhenValueChanges,
                                (editor, cancellationToken) => MakeWithBackingFieldNotifyWhenValueChanges(editor, propertyDeclaration, invoker, semanticModel, cancellationToken),
                                NotifyWhenValueChanges,
                                diagnostic);

                            context.RegisterDocumentEditorFix(
                                "Notify.",
                                (editor, cancellationToken) => MakeWithBackingFieldNotify(editor, propertyDeclaration, invoker, semanticModel, cancellationToken),
                                "Notify.",
                                diagnostic);
                        }
                    }
                }
            }
        }
Example #13
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);
                    }
                }
            }
        }
        /// <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 invocationStatement = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                          .FirstAncestorOrSelf <ExpressionStatementSyntax>();
                var setter = invocationStatement?.FirstAncestorOrSelf <AccessorDeclarationSyntax>();
                if (setter?.IsKind(SyntaxKind.SetAccessorDeclaration) != true ||
                    setter.Body == null)
                {
                    continue;
                }

                if (Property.TrySingleAssignmentInSetter(setter, out var assignment))
                {
                    var statementSyntax = assignment.FirstAncestorOrSelf <ExpressionStatementSyntax>();
                    if (setter.Body.Statements.First() != statementSyntax)
                    {
                        continue;
                    }

                    context.RegisterDocumentEditorFix(
                        "Check that value is different before notifying.",
                        (editor, cancellationToken) => AddCheckIfDifferent(editor, assignment, cancellationToken),
                        this.GetType(),
                        diagnostic);

                    var type = semanticModel.GetDeclaredSymbolSafe(
                        setter.FirstAncestor <ClassDeclarationSyntax>(),
                        context.CancellationToken);
                    if (setter.Body.Statements.Count == 2 &&
                        ReferenceEquals(setter.Body.Statements[0], statementSyntax) &&
                        PropertyChanged.TryGetSetAndRaise(type, semanticModel, context.CancellationToken, out var setAndRaiseMethod))
                    {
                        context.RegisterDocumentEditorFix(
                            $"Use {setAndRaiseMethod.ContainingType.MetadataName}.{setAndRaiseMethod.MetadataName}",
                            (editor, cancellationToken) => UseSetAndRaise(editor, setter, assignment, setAndRaiseMethod),
                            $"Use {setAndRaiseMethod.ContainingType.MetadataName}.{setAndRaiseMethod.MetadataName}",
                            diagnostic);
                    }
                }

                if (Property.TryFindSingleSetAndRaise(setter, semanticModel, context.CancellationToken, out var setAndRaise))
                {
                    if (setAndRaise.Parent is ExpressionStatementSyntax setAndRaiseStatement)
                    {
                        if (invocationStatement.Parent is BlockSyntax block &&
                            block.Statements.IndexOf(setAndRaiseStatement) == block.Statements.IndexOf(invocationStatement) - 1)
                        {
                            context.RegisterDocumentEditorFix(
                                "Check that value is different before notifying.",
                                (editor, cancellationToken) => CreateIf(editor, setAndRaiseStatement, invocationStatement),
                                this.GetType(),
                                diagnostic);
                        }
                    }
                    else if (setAndRaise.Parent is IfStatementSyntax ifSetAndRaiseStatement)
                    {
                        if (invocationStatement.Parent is BlockSyntax block &&
                            block.Statements.IndexOf(ifSetAndRaiseStatement) == block.Statements.IndexOf(invocationStatement) - 1)
                        {
                            context.RegisterDocumentEditorFix(
                                "Check that value is different before notifying.",
                                (editor, cancellationToken) => AddToIf(editor, ifSetAndRaiseStatement, invocationStatement),
                                this.GetType(),
                                diagnostic);
                        }
                    }
                }
            }
        }
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            foreach (var diagnostic in context.Diagnostics)
            {
                if (diagnostic.Id == IDISP001DisposeCreated.DiagnosticId)
                {
                    if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out LocalDeclarationStatementSyntax statement))
                    {
                        switch (statement.Parent)
                        {
                        case BlockSyntax block:
                            context.RegisterDocumentEditorFix(
                                "Add using to end of block.",
                                (editor, _) => AddUsingToEndOfBlock(editor, block, statement),
                                diagnostic);
                            break;

                        case SwitchSectionSyntax switchSection:
                            context.RegisterDocumentEditorFix(
                                "Add using to end of block.",
                                (editor, _) => AddUsingToEndOfBlock(editor, switchSection, statement),
                                diagnostic);
                            break;
                        }
                    }
                    else if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out ExpressionStatementSyntax expressionStatement) &&
                             expressionStatement.Parent is BlockSyntax expressionStatementBlock)
                    {
                        context.RegisterDocumentEditorFix(
                            "Add using to end of block.",
                            (editor, _) => AddUsingToEndOfBlock(editor, expressionStatementBlock, expressionStatement),
                            diagnostic);
                    }
                    else if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out ArgumentSyntax argument) &&
                             argument.Parent is ArgumentListSyntax argumentList &&
                             argumentList.Parent is InvocationExpressionSyntax invocation &&
                             invocation.Parent is IfStatementSyntax ifStatement &&
                             ifStatement.Statement is BlockSyntax ifBlock)
                    {
                        context.RegisterDocumentEditorFix(
                            "Add using to end of block.",
                            (editor, _) => AddUsingToEndOfBlock(editor, ifBlock, argument.Expression),
                            diagnostic);
                    }
                }
                else if (diagnostic.Id == IDISP004DontIgnoreCreated.DiagnosticId &&
                         syntaxRoot.TryFindNodeOrAncestor(diagnostic, out ExpressionStatementSyntax statement) &&
                         statement.Parent is BlockSyntax block)
                {
                    context.RegisterDocumentEditorFix(
                        "Add using to end of block.",
                        (editor, _) => AddUsingToEndOfBlock(editor, block, statement),
                        diagnostic);
                }
                else if (diagnostic.Id == IDISP017PreferUsing.DiagnosticId &&
                         syntaxRoot.TryFindNode(diagnostic, out InvocationExpressionSyntax invocation))
                {
                    context.RegisterDocumentEditorFix(
                        "Replace with using.",
                        (editor, cancellationToken) => ReplaceWithUsing(editor, invocation, cancellationToken),
                        diagnostic);
                }
            }
        }
Example #16
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 node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                if (node.FirstAncestorOrSelf <ParameterSyntax>() is ParameterSyntax parameter)
                {
                    context.RegisterDocumentEditorFix(
                        "Use [CallerMemberName]",
                        (editor, x) => editor.ReplaceNode(
                            parameter,
                            AsCallerMemberName(parameter)),
                        this.GetType(),
                        diagnostic);
                    continue;
                }

                if (node.FirstAncestorOrSelf <ArgumentSyntax>() is ArgumentSyntax argument)
                {
                    if (argument.Parent.Parent is InvocationExpressionSyntax invocation &&
                        semanticModel.GetSymbolSafe(invocation, context.CancellationToken) is IMethodSymbol method &&
                        method.TryGetMatchingParameter(argument, out var parameterSymbol))
                    {
                        if (parameterSymbol.IsCallerMemberName())
                        {
                            context.RegisterDocumentEditorFix(
                                "Use [CallerMemberName]",
                                (editor, _) => editor.RemoveNode(argument),
                                this.GetType(),
                                diagnostic);
                        }
                        else if (SymbolExt.TrySingleDeclaration((ISymbol)parameterSymbol, context.CancellationToken, out ParameterSyntax parameterSyntax))
                        {
                            context.RegisterDocumentEditorFix(
                                "Use [CallerMemberName]",
                                (editor, x) =>
                            {
                                editor.ReplaceNode(
                                    parameterSyntax,
                                    AsCallerMemberName(parameterSyntax));
                                editor.RemoveNode(argument);
                            },
                                this.GetType(),
                                diagnostic);
                        }
                    }
                }
            }
        }
Example #17
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);

            var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);

            foreach (var diagnostic in context.Diagnostics)
            {
                if (diagnostic.Properties.TryGetValue(INPC003NotifyWhenPropertyChanges.PropertyNameKey, out var property))
                {
                    var expression = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                     .FirstAncestorOrSelf <ExpressionSyntax>();
                    var typeDeclaration = expression.FirstAncestorOrSelf <TypeDeclarationSyntax>();
                    var type            = semanticModel.GetDeclaredSymbolSafe(typeDeclaration, context.CancellationToken);
                    if (PropertyChanged.TryGetOnPropertyChanged(type, semanticModel, context.CancellationToken, out var invoker) &&
                        invoker.Parameters[0].Type == KnownSymbol.String)
                    {
                        var invocation = expression.FirstAncestorOrSelf <InvocationExpressionSyntax>();
                        var method     = (IMethodSymbol)semanticModel.GetSymbolSafe(invocation, context.CancellationToken);
                        if (PropertyChanged.IsSetAndRaise(method, semanticModel, context.CancellationToken) != AnalysisResult.No)
                        {
                            if (invocation.Parent is ExpressionStatementSyntax ||
                                invocation.Parent is ArrowExpressionClauseSyntax)
                            {
                                context.RegisterDocumentEditorFix(
                                    $"Notify that property {property} changes.",
                                    (editor, cancellationToken) => MakeNotifyCreateIf(
                                        editor,
                                        invocation,
                                        property,
                                        invoker,
                                        underscoreFields),
                                    this.GetType(),
                                    diagnostic);
                                continue;
                            }

                            if (invocation.Parent is IfStatementSyntax ifStatement)
                            {
                                context.RegisterDocumentEditorFix(
                                    $"Notify that property {property} changes.",
                                    (editor, _) => MakeNotifyInIf(
                                        editor,
                                        ifStatement,
                                        property,
                                        invoker,
                                        underscoreFields),
                                    this.GetType(),
                                    diagnostic);
                                continue;
                            }

                            if (invocation.Parent is PrefixUnaryExpressionSyntax unary &&
                                unary.IsKind(SyntaxKind.LogicalNotExpression) &&
                                unary.Parent is IfStatementSyntax ifStatement2 &&
                                ifStatement2.IsReturnOnly())
                            {
                                context.RegisterDocumentEditorFix(
                                    $"Notify that property {property} changes.",
                                    (editor, _) => MakeNotify(
                                        editor,
                                        expression,
                                        property,
                                        invoker,
                                        underscoreFields),
                                    this.GetType(),
                                    diagnostic);
                                continue;
                            }
                        }

                        context.RegisterDocumentEditorFix(
                            $"Notify that property {property} changes.",
                            (editor, _) => MakeNotify(
                                editor,
                                expression,
                                property,
                                invoker,
                                underscoreFields),
                            this.GetType(),
                            diagnostic);
                    }
                }
            }
        }