internal static bool TrySingleReturned(AccessorDeclarationSyntax getter, [NotNullWhen(true)] out ExpressionSyntax?result) { if (getter.ExpressionBody is { } getterExpressionBody) { result = getterExpressionBody.Expression; return(result != null); } if (getter.Body is { } body) { if (body.Statements.Count == 0) { result = null; return(false); } if (body.Statements.TrySingle(out var statement)) { if (statement is ReturnStatementSyntax returnStatement) { result = returnStatement.Expression; return(result != null); } } return(ReturnExpressionsWalker.TryGetSingle(getter, out result)); } result = null; return(false); }
private static void Handle(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } if (context.Node is PropertyDeclarationSyntax propertyDeclaration && context.ContainingSymbol is IPropertySymbol property) { if (propertyDeclaration.ExpressionBody is ArrowExpressionClauseSyntax expressionBody && IsProperty(expressionBody.Expression, property)) { context.ReportDiagnostic(Diagnostic.Create(INPC015PropertyIsRecursive.Descriptor, expressionBody.Expression.GetLocation(), "Expression body returns property, infinite recursion")); } if (propertyDeclaration.TryGetGetter(out var getter)) { using (var returnWalker = ReturnExpressionsWalker.Borrow(getter)) { if (returnWalker.ReturnValues.TryFirst(x => IsProperty(x, property), out var recursiveReturnValue)) { context.ReportDiagnostic(Diagnostic.Create(INPC015PropertyIsRecursive.Descriptor, recursiveReturnValue.GetLocation(), "Getter returns property, infinite recursion")); } } } if (propertyDeclaration.TryGetSetter(out var setter)) { using (var assignmentWalker = AssignmentWalker.Borrow(setter)) { if (assignmentWalker.Assignments.TryFirst(x => IsProperty(x.Left, property), out var recursiveAssignment)) { context.ReportDiagnostic(Diagnostic.Create(INPC015PropertyIsRecursive.Descriptor, recursiveAssignment.Left.GetLocation(), "Setter assigns property, infinite recursion")); } if (getter != null) { if (property.ContainingType.Is(KnownSymbol.INotifyPropertyChanged) && Property.ShouldNotify(propertyDeclaration, property, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(INPC002MutablePublicPropertyShouldNotify.Descriptor, propertyDeclaration.GetLocation(), property.Name)); } if (assignmentWalker.Assignments.TrySingle(out var singleAssignment) && ReturnExpressionsWalker.TryGetSingle(getter, out var singleReturnValue) && !MemberPath.Uses(singleAssignment.Left, singleReturnValue, context)) { context.ReportDiagnostic(Diagnostic.Create(INPC010GetAndSetSame.Descriptor, propertyDeclaration.GetLocation())); } } } } } }