예제 #1
0
        public static async Task ComputeRefactoringAsync(
            RefactoringContext context,
            PropertyDeclarationSyntax property)
        {
            AccessorDeclarationSyntax setter = property.Setter();

            if (setter == null)
            {
                return;
            }

            if (setter.IsKind(SyntaxKind.InitAccessorDeclaration))
            {
                return;
            }

            ExpressionSyntax expression = GetExpression();

            if (expression == null)
            {
                return;
            }

            SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression);

            if (!simpleAssignment.Success)
            {
                return;
            }

            if (!simpleAssignment.Left.IsKind(SyntaxKind.IdentifierName))
            {
                return;
            }

            if (!(simpleAssignment.Right is IdentifierNameSyntax identifierName))
            {
                return;
            }

            if (identifierName.Identifier.ValueText != "value")
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            INamedTypeSymbol containingType = semanticModel
                                              .GetDeclaredSymbol(property, context.CancellationToken)?
                                              .ContainingType;

            if (containingType == null)
            {
                return;
            }

            if (!containingType.Implements(MetadataNames.System_ComponentModel_INotifyPropertyChanged, allInterfaces: true))
            {
                return;
            }

            IMethodSymbol methodSymbol = SymbolUtility.FindMethodThatRaisePropertyChanged(containingType, expression.SpanStart, semanticModel);

            if (methodSymbol == null)
            {
                return;
            }

            Document document = context.Document;

            context.RegisterRefactoring(
                "Notify when property change",
                ct => RefactorAsync(document, property, methodSymbol.Name, ct),
                RefactoringIdentifiers.NotifyWhenPropertyChange);

            ExpressionSyntax GetExpression()
            {
                BlockSyntax body = setter.Body;

                if (body != null)
                {
                    if (body.Statements.SingleOrDefault(shouldThrow: false) is ExpressionStatementSyntax expressionStatement)
                    {
                        return(expressionStatement.Expression);
                    }
                }
                else
                {
                    return(setter.ExpressionBody?.Expression);
                }

                return(null);
            }
        }
예제 #2
0
        internal static bool IsFixable(
            IndexerDeclarationSyntax indexerDeclaration,
            AccessorDeclarationSyntax accessor,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            switch (accessor.Kind())
            {
            case SyntaxKind.GetAccessorDeclaration:
            {
                ExpressionSyntax expression = GetGetAccessorExpression(accessor);

                if (!(expression is ElementAccessExpressionSyntax elementAccess))
                {
                    return(false);
                }

                if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true)
                {
                    return(false);
                }

                if (elementAccess.ArgumentList == null)
                {
                    return(false);
                }

                IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken);

                if (propertySymbol == null)
                {
                    return(false);
                }

                IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty;

                if (overriddenProperty == null)
                {
                    return(false);
                }

                ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken);

                return(SymbolEqualityComparer.Default.Equals(overriddenProperty, symbol) &&
                       CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) &&
                       CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters));
            }

            case SyntaxKind.SetAccessorDeclaration:
            {
                ExpressionSyntax expression = GetSetAccessorExpression(accessor);

                SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression);

                if (!assignment.Success)
                {
                    return(false);
                }

                if (assignment.Left.Kind() != SyntaxKind.ElementAccessExpression)
                {
                    return(false);
                }

                var elementAccess = (ElementAccessExpressionSyntax)assignment.Left;

                if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true)
                {
                    return(false);
                }

                if (elementAccess.ArgumentList == null)
                {
                    return(false);
                }

                if (assignment.Right.Kind() != SyntaxKind.IdentifierName)
                {
                    return(false);
                }

                var identifierName = (IdentifierNameSyntax)assignment.Right;

                if (identifierName.Identifier.ValueText != "value")
                {
                    return(false);
                }

                IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken);

                if (propertySymbol == null)
                {
                    return(false);
                }

                IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty;

                if (overriddenProperty == null)
                {
                    return(false);
                }

                ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken);

                return(SymbolEqualityComparer.Default.Equals(overriddenProperty, symbol) &&
                       CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) &&
                       CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters));
            }

            case SyntaxKind.UnknownAccessorDeclaration:
            {
                return(false);
            }

            default:
            {
                Debug.Fail(accessor.Kind().ToString());
                return(false);
            }
            }
        }
예제 #3
0
        private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context)
        {
            var assignmentExpression = (AssignmentExpressionSyntax)context.Node;

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression))
            {
                return;
            }

            ExpressionSyntax right = assignmentInfo.Right;

            if (!CanBeReplacedWithCompoundAssignment(right.Kind()))
            {
                return;
            }

            BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right);

            if (!binaryInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left))
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)right;

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCompoundAssignment, assignmentExpression, GetCompoundAssignmentOperatorText(binaryExpression));
            DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, binaryExpression.Left);

            bool CanBeReplacedWithCompoundAssignment(SyntaxKind kind)
            {
                switch (kind)
                {
                case SyntaxKind.AddExpression:
                case SyntaxKind.SubtractExpression:
                case SyntaxKind.MultiplyExpression:
                case SyntaxKind.DivideExpression:
                case SyntaxKind.ModuloExpression:
                case SyntaxKind.BitwiseAndExpression:
                case SyntaxKind.ExclusiveOrExpression:
                case SyntaxKind.BitwiseOrExpression:
                case SyntaxKind.LeftShiftExpression:
                case SyntaxKind.RightShiftExpression:
                    return(true);

                case SyntaxKind.CoalesceExpression:
                    return(((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp8);

                default:
                    return(false);
                }
            }
        }
예제 #4
0
        internal static bool IsFixable(
            PropertyDeclarationSyntax propertyDeclaration,
            AccessorDeclarationSyntax accessor,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            switch (accessor.Kind())
            {
            case SyntaxKind.GetAccessorDeclaration:
            {
                ExpressionSyntax expression = GetGetAccessorExpression(accessor);

                if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) != true)
                {
                    return(false);
                }

                var memberAccess = (MemberAccessExpressionSyntax)expression;

                if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true)
                {
                    return(false);
                }

                SimpleNameSyntax simpleName = memberAccess.Name;

                IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken);

                if (propertySymbol == null)
                {
                    return(false);
                }

                IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty;

                if (overriddenProperty == null)
                {
                    return(false);
                }

                ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken);

                return(SymbolEqualityComparer.Default.Equals(overriddenProperty, symbol));
            }

            case SyntaxKind.SetAccessorDeclaration:
            {
                ExpressionSyntax expression = GetSetAccessorExpression(accessor);

                SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression);

                if (!assignment.Success)
                {
                    return(false);
                }

                if (assignment.Left.Kind() != SyntaxKind.SimpleMemberAccessExpression)
                {
                    return(false);
                }

                var memberAccess = (MemberAccessExpressionSyntax)assignment.Left;

                if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true)
                {
                    return(false);
                }

                if (assignment.Right.Kind() != SyntaxKind.IdentifierName)
                {
                    return(false);
                }

                var identifierName = (IdentifierNameSyntax)assignment.Right;

                if (identifierName.Identifier.ValueText != "value")
                {
                    return(false);
                }

                SimpleNameSyntax simpleName = memberAccess.Name;

                if (simpleName == null)
                {
                    return(false);
                }

                IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken);

                if (propertySymbol == null)
                {
                    return(false);
                }

                IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty;

                if (overriddenProperty == null)
                {
                    return(false);
                }

                ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken);

                return(SymbolEqualityComparer.Default.Equals(overriddenProperty, symbol));
            }

            case SyntaxKind.UnknownAccessorDeclaration:
            {
                return(false);
            }

            default:
            {
                Debug.Fail(accessor.Kind().ToString());
                return(false);
            }
            }
        }
        public override bool IsFixableStatement(
            StatementSyntax statement,
            string name,
            ITypeSymbol typeSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (statement.SpanOrLeadingTriviaContainsDirectives())
            {
                return(false);
            }

            if (!(statement is ExpressionStatementSyntax expressionStatement))
            {
                return(false);
            }

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(expressionStatement.Expression);

            if (!assignmentInfo.Success)
            {
                return(false);
            }

            if (name != (assignmentInfo.Left as IdentifierNameSyntax)?.Identifier.ValueText)
            {
                return(false);
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(assignmentInfo.Right);

            if (!invocationInfo.Success)
            {
                return(false);
            }

            if (!(WalkDownMethodChain(invocationInfo).Expression is IdentifierNameSyntax identifierName))
            {
                return(false);
            }

            if (name != identifierName.Identifier.ValueText)
            {
                return(false);
            }

            IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(invocationInfo.InvocationExpression, cancellationToken);

            if (methodSymbol == null)
            {
                return(false);
            }

            if (!SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, typeSymbol))
            {
                return(false);
            }

            if (IsReferenced(invocationInfo.InvocationExpression, identifierName, name, semanticModel, cancellationToken))
            {
                return(false);
            }

            return(true);
        }