private static void HandlePotentialSetMethod(SyntaxNodeAnalysisContext context, BlockSyntax body) { if (body == null) { return; } using (var pooled = ClrSetterWalker.Create(context.SemanticModel, context.CancellationToken, context.Node)) { if (pooled.Item.HasError) { return; } if (pooled.Item.IsSuccess) { foreach (var statement in body.Statements) { if ((statement as ExpressionStatementSyntax)?.Expression != pooled.Item.SetValue && (statement as ExpressionStatementSyntax)?.Expression != pooled.Item.SetCurrentValue) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, statement.GetLocation())); return; } } } } }
/// <summary> /// Get the backing fields for the <paramref name="propertyDeclaration"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field /// </summary> internal static bool TryGetBackingFields(PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken, out IFieldSymbol getField, out IFieldSymbol setField) { getField = null; setField = null; if (propertyDeclaration.TryGetAccessorDeclaration(SyntaxKind.GetAccessorDeclaration, out AccessorDeclarationSyntax getAccessor) && propertyDeclaration.TryGetAccessorDeclaration(SyntaxKind.SetAccessorDeclaration, out AccessorDeclarationSyntax setAccessor)) { using (var pooled = ClrGetterWalker.Create(semanticModel, cancellationToken, getAccessor)) { using (var setterWalker = ClrSetterWalker.Create(semanticModel, cancellationToken, setAccessor)) { if (pooled.Item.HasError || setterWalker.Item.HasError) { return(false); } if (pooled.Item.IsSuccess && pooled.Item.Property.TryGetSymbol(semanticModel, cancellationToken, out getField) && setterWalker.Item.IsSuccess && setterWalker.Item.Property.TryGetSymbol(semanticModel, cancellationToken, out setField)) { return(true); } var property = semanticModel.GetSymbolSafe(propertyDeclaration, cancellationToken) as IPropertySymbol; return(TryGetBackingFieldsByName(property, out getField, out setField)); } } } return(false); }
public static ClrSetterWalker Create(SemanticModel semanticModel, CancellationToken cancellationToken, SyntaxNode setter) { ClrSetterWalker walker; if (!Cache.TryDequeue(out walker)) { walker = new ClrSetterWalker(); } walker.HasError = false; walker.SetValue = null; walker.SetCurrentValue = null; walker.semanticModel = semanticModel; walker.cancellationToken = cancellationToken; walker.Visit(setter); return(walker); }
private static bool IsAttachedSetMethod(MethodDeclarationSyntax method, SemanticModel semanticModel, CancellationToken cancellationToken, out IFieldSymbol setField) { setField = null; if (method == null || method.ParameterList.Parameters.Count != 2 || !method.ReturnType.IsVoid() || !method.Modifiers.Any(SyntaxKind.StaticKeyword)) { return(false); } using (var walker = ClrSetterWalker.Create(semanticModel, cancellationToken, method)) { if (!walker.IsSuccess) { return(false); } var memberAccess = (walker.SetValue?.Expression ?? walker.SetCurrentValue?.Expression) as MemberAccessExpressionSyntax; var member = memberAccess?.Expression as IdentifierNameSyntax; if (memberAccess == null || member == null || !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return(false); } if (method.ParameterList.Parameters[0].Identifier.ValueText != member.Identifier.ValueText) { return(false); } using (var valueWalker = ValueWalker.Create(method.ParameterList.Parameters[1].Identifier, memberAccess.Parent)) { if (!valueWalker.UsesValue) { return(false); } } return(walker.Property.TryGetSymbol(semanticModel, cancellationToken, out setField)); } }