internal static bool TryGetRegisteredName(InvocationExpressionSyntax invocation, SemanticModel semanticModel, CancellationToken cancellationToken, out ArgumentSyntax nameArg, out string registeredName) { nameArg = null; registeredName = null; if (invocation == null) { return(false); } if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out var method) || TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out method) || TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out method) || TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out method)) { return(method.TryFindParameter("name", out var parameter) && invocation.TryFindArgument(parameter, out nameArg) && nameArg.TryGetStringValue(semanticModel, cancellationToken, out registeredName)); } if (invocation.Expression is MemberAccessExpressionSyntax memberAccess && (TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) || TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _))) { if (semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out var symbol) && BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty)) { return(TryGetRegisteredName(fieldOrProperty, semanticModel, cancellationToken, out nameArg, out registeredName)); } return(false); } return(false); }
internal static bool TryGetPropertyByName(BackingFieldOrProperty fieldOrProperty, out IPropertySymbol property) { property = null; if (IsPotentialDependencyPropertyBackingField(fieldOrProperty) || IsPotentialDependencyPropertyKeyBackingField(fieldOrProperty)) { var suffix = IsPotentialDependencyPropertyBackingField(fieldOrProperty) ? "Property" : "PropertyKey"; foreach (var symbol in fieldOrProperty.ContainingType.GetMembers()) { if (symbol is IPropertySymbol candidate) { if (!fieldOrProperty.Name.IsParts(candidate.Name, suffix)) { continue; } if (property != null) { property = null; return(false); } property = candidate; } } } return(property != null); }
internal static bool TryGetRegisteredType(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol result) { result = null; if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out _)) { return(invocation.TryGetArgumentAtIndex(1, out var typeArg) && typeArg.Expression is TypeOfExpressionSyntax typeOf && TypeOf.TryGetType(typeOf, backing.ContainingType, semanticModel, cancellationToken, out result)); } if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) && !source.Symbol.Equals(backing.Symbol)) { return(TryGetRegisteredType(source, semanticModel, cancellationToken, out result)); } if (backing.Symbol.Locations.All(x => !x.IsInSource) && TryGetPropertyByName(backing, out var property)) { result = property.Type; return(true); } return(false); }
internal static bool TryGetDependencyPropertyKeyFieldOrProperty(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result) { result = default; if (backing.TryGetAssignedValue(cancellationToken, out var value) && semanticModel.TryGetSymbol(value, cancellationToken, out ISymbol symbol)) { if (symbol is IMethodSymbol method) { return(method == KnownSymbols.DependencyProperty.AddOwner && value is InvocationExpressionSyntax invocation && invocation.Expression is MemberAccessExpressionSyntax member && semanticModel.TryGetSymbol(member.Expression, cancellationToken, out ISymbol candidate) && BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out result) && TryGetDependencyPropertyKeyFieldOrProperty(result, semanticModel, cancellationToken, out result)); } else { return(symbol is IPropertySymbol property && property == KnownSymbols.DependencyPropertyKey.DependencyProperty && value is MemberAccessExpressionSyntax memberAccess && semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out ISymbol candidate) && BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out result)); } } return(false); }
internal static bool IsAttachedGet(MethodDeclarationSyntax method, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax call, out BackingFieldOrProperty getField) { call = null; getField = default(BackingFieldOrProperty); if (method == null || method.ParameterList.Parameters.Count != 1 || method.ReturnType.IsVoid() || !method.Modifiers.Any(SyntaxKind.StaticKeyword)) { return(false); } using (var walker = ClrGetterWalker.Borrow(semanticModel, cancellationToken, method)) { call = walker.GetValue; var memberAccess = walker.GetValue?.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); } return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out getField)); } }
internal static bool TryGetRegisteredName(InvocationExpressionSyntax invocation, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName) { registeredName = null; if (invocation == null) { return(false); } if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out _) || TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out _) || TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out _) || TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out _)) { return(invocation.TryGetArgumentAtIndex(0, out var nameArg) && nameArg.TryGetStringValue(semanticModel, cancellationToken, out registeredName)); } if (invocation.Expression is MemberAccessExpressionSyntax memberAccess && (TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) || TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _))) { if (BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(memberAccess.Expression, cancellationToken), out var fieldOrProperty)) { return(TryGetRegisteredName(fieldOrProperty, semanticModel, cancellationToken, out registeredName)); } return(false); } return(false); }
internal static bool TryGetRegisteredName(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out ArgumentSyntax nameArg, out string result) { nameArg = null; result = null; if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out var method)) { return(method.TryFindParameter("name", out var parameter) && invocation.TryFindArgument(parameter, out nameArg) && nameArg.TryGetStringValue(semanticModel, cancellationToken, out result)); } if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) && !source.Symbol.Equals(backing.Symbol)) { return(TryGetRegisteredName(source, semanticModel, cancellationToken, out nameArg, out result)); } if (backing.Symbol.Locations.All(x => !x.IsInSource) && TryGetPropertyByName(backing, out var property)) { result = property.Name; return(true); } return(false); }
/// <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 BackingFieldOrProperty getField, out BackingFieldOrProperty setField) { getField = default; setField = default; if (propertyDeclaration.TryGetGetter(out var getAccessor) && propertyDeclaration.TryGetSetter(out var setAccessor)) { using (var getterWalker = ClrGetterWalker.Borrow(semanticModel, cancellationToken, getAccessor)) { using (var setterWalker = ClrSetterWalker.Borrow(semanticModel, cancellationToken, setAccessor)) { if (getterWalker.HasError || setterWalker.HasError) { return(false); } if (getterWalker.IsSuccess && BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(getterWalker.Property.Expression, cancellationToken), out getField) && setterWalker.IsSuccess && BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(setterWalker.Property.Expression, cancellationToken), out setField)) { return(true); } var property = semanticModel.GetSymbolSafe(propertyDeclaration, cancellationToken) as IPropertySymbol; return(TryGetBackingFieldsByName(property, semanticModel.Compilation, out getField, out setField)); } } } return(false); }
private static void Handle(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } if (context.Node is InvocationExpressionSyntax invocation && context.ContainingSymbol.IsStatic) { if (invocation.TryGetArgumentAtIndex(2, out var argument) && (DependencyProperty.TryGetRegisterCall(invocation, context.SemanticModel, context.CancellationToken, out _) || DependencyProperty.TryGetRegisterReadOnlyCall(invocation, context.SemanticModel, context.CancellationToken, out _) || DependencyProperty.TryGetRegisterAttachedCall(invocation, context.SemanticModel, context.CancellationToken, out _) || DependencyProperty.TryGetRegisterAttachedReadOnlyCall(invocation, context.SemanticModel, context.CancellationToken, out _))) { HandleArgument(context, argument); } else if (invocation.TryGetArgumentAtIndex(0, out argument)) { if (DependencyProperty.TryGetAddOwnerCall(invocation, context.SemanticModel, context.CancellationToken, out _)) { HandleArgument(context, argument); } else if (DependencyProperty.TryGetOverrideMetadataCall(invocation, context.SemanticModel, context.CancellationToken, out _) && invocation.Expression is MemberAccessExpressionSyntax memberAccess && BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(memberAccess.Expression, context.CancellationToken), out var fieldOrProperty) && context.ContainingSymbol.ContainingType.IsAssignableTo(fieldOrProperty.ContainingType, context.Compilation)) { HandleArgument(context, argument); } } } }
private ClrProperty(BackingFieldOrProperty backingGet, BackingFieldOrProperty backingSet, InvocationExpressionSyntax?getValue, InvocationExpressionSyntax?setValue) { this.BackingGet = backingGet; this.BackingSet = backingSet; this.GetValue = getValue; this.SetValue = setValue; }
/// <inheritdoc/> protected override async Task RegisterCodeFixesAsync(DocumentEditorCodeFixContext context) { var document = context.Document; var syntaxRoot = await document.GetSyntaxRootAsync(context.CancellationToken) .ConfigureAwait(false); var semanticModel = await 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; } if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out MemberDeclarationSyntax member) && semanticModel.TryGetSymbol(member, context.CancellationToken, out ISymbol symbol) && BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty) && DependencyProperty.TryGetRegisteredName(fieldOrProperty, semanticModel, context.CancellationToken, out var name)) { context.RegisterCodeFix( "Add standard documentation.", (editor, _) => editor.ReplaceNode(member, x => x.WithDocumentationText($"/// <summary>Identifies the <see cref=\"{name}\"/> dependency property.</summary>")), this.GetType(), diagnostic); } } }
internal static bool IsAttachedSet(MethodDeclarationSyntax method, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax setValueCall, out BackingFieldOrProperty setField) { setValueCall = null; setField = default(BackingFieldOrProperty); if (method == null || method.ParameterList.Parameters.Count != 2 || !method.ReturnType.IsVoid() || !method.Modifiers.Any(SyntaxKind.StaticKeyword)) { return(false); } using (var walker = ClrSetterWalker.Borrow(semanticModel, cancellationToken, method)) { if (!walker.IsSuccess) { return(false); } setValueCall = walker.SetValue ?? walker.SetCurrentValue; if (setValueCall.Expression is MemberAccessExpressionSyntax memberAccess && memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression) && memberAccess.Expression is IdentifierNameSyntax member) { if (method.ParameterList.Parameters[0].Identifier.ValueText != member.Identifier.ValueText) { return(false); } if (setValueCall.TryGetArgumentAtIndex(1, out var arg) && method.ParameterList.Parameters.TryElementAt(1, out var parameter)) { if (arg.Expression is IdentifierNameSyntax argIdentifier && argIdentifier.Identifier.ValueText == parameter.Identifier.ValueText) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField)); } if (arg.Expression is InvocationExpressionSyntax invocation && invocation.TrySingleArgument(out var nestedArg) && nestedArg.Expression is IdentifierNameSyntax nestedArgId && nestedArgId.Identifier.ValueText == parameter.Identifier.ValueText) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField)); } if (arg.Expression is ConditionalExpressionSyntax ternary && ternary.Condition is IdentifierNameSyntax conditionIdentifier && conditionIdentifier.Identifier.ValueText == parameter.Identifier.ValueText) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField)); } } } return(false); } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MemberDeclarationSyntax memberDeclaration) { if (BackingFieldOrProperty.TryCreateForDependencyProperty(context.ContainingSymbol, out var backingMember)) { if (DependencyProperty.TryGetRegisteredName(backingMember, context.SemanticModel, context.CancellationToken, out _, out var registeredName)) { if (backingMember.Type == KnownSymbols.DependencyProperty && !backingMember.Name.IsParts(registeredName, "Property")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0001BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Property"), backingMember.Name, registeredName)); } if (backingMember.Type == KnownSymbols.DependencyPropertyKey && !backingMember.Name.IsParts(registeredName, "PropertyKey")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0002BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "PropertyKey"), backingMember.Name, registeredName)); } if (context.ContainingSymbol.ContainingType.TryFindProperty(registeredName, out _) && context.ContainingSymbol.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public) && !HasStandardText(memberDeclaration, registeredName, out var comment)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0060DocumentDependencyPropertyBackingMember, comment == null ? BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation() : comment.GetLocation(), properties: ImmutableDictionary <string, string> .Empty.Add(nameof(CrefParameterSyntax), registeredName))); } if (DependencyProperty.TryGetRegisteredType(backingMember, context.SemanticModel, context.CancellationToken, out var type) && type.Is(KnownSymbols.Style) && !TryFindStyleTypedPropertyAttribute(memberDeclaration, registeredName, context.SemanticModel, context.CancellationToken) && backingMember.FieldOrProperty.Symbol.DeclaredAccessibility.IsEither(Accessibility.Public, Accessibility.Internal)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0176StyleTypedPropertyMissing, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add( nameof(AttributeListSyntax), $"[StyleTypedProperty(Property = {(context.ContainingSymbol.ContainingType.TryFindProperty(registeredName, out _) ? $"nameof({registeredName})" : $"\"{registeredName}\"")}, StyleTargetType = typeof(TYPE))]"),
internal static bool TryCreateCandidate(ISymbol symbol, out BackingFieldOrProperty result) { if (symbol != null && FieldOrProperty.TryCreate(symbol, out var fieldOrProperty) && fieldOrProperty.Type.IsEither(KnownSymbol.DependencyProperty, KnownSymbol.DependencyPropertyKey)) { result = new BackingFieldOrProperty(fieldOrProperty); return(true); } result = default(BackingFieldOrProperty); return(false); }
internal static bool TryGetDependencyPropertyKeyFieldOrProperty(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result) { result = default; if (backing.TryGetAssignedValue(cancellationToken, out var value) && semanticModel.TryGetSymbol(value, cancellationToken, out var symbol)) { if (symbol is IMethodSymbol method) { return(method == KnownSymbols.DependencyProperty.AddOwner && value is InvocationExpressionSyntax { Expression : MemberAccessExpressionSyntax { Expression : { } expression } } &&
internal static bool TryGetRegisterInvocationRecursive(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax result, out IMethodSymbol symbol) { if (TryGetDependencyPropertyKeyFieldOrProperty(fieldOrProperty, semanticModel, cancellationToken, out var keyField)) { return(TryGetRegisterInvocationRecursive(keyField, semanticModel, cancellationToken, out result, out symbol)); } if (TryGetDependencyAddOwnerSourceField(fieldOrProperty, semanticModel, cancellationToken, out var addOwnerSource)) { return(TryGetRegisterInvocationRecursive(addOwnerSource, semanticModel, cancellationToken, out result, out symbol)); } return(TryGetRegisterInvocation(fieldOrProperty, semanticModel, cancellationToken, out result, out symbol)); }
internal static bool TryGetDependencyAddOwnerSourceField(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result) { result = default; if (fieldOrProperty.TryGetAssignedValue(cancellationToken, out var value) && value is InvocationExpressionSyntax invocation && semanticModel.TryGetSymbol(invocation, KnownSymbols.DependencyProperty.AddOwner, cancellationToken, out _)) { var addOwner = (MemberAccessExpressionSyntax)invocation.Expression; return(BackingFieldOrProperty.TryCreateForDependencyProperty( semanticModel.GetSymbolSafe(addOwner.Expression, cancellationToken), out result)); } return(false); }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is InvocationExpressionSyntax invocation && DependencyProperty.TryGetOverrideMetadataCall(invocation, context.SemanticModel, context.CancellationToken, out var method) && invocation.Expression is MemberAccessExpressionSyntax memberAccess && context.SemanticModel.TryGetSymbol(memberAccess.Expression, context.CancellationToken, out ISymbol candidate) && BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out var fieldOrProperty) && method.TryFindParameter(KnownSymbols.PropertyMetadata, out var parameter) && invocation.TryFindArgument(parameter, out var metadataArg)) { if (fieldOrProperty.TryGetAssignedValue(context.CancellationToken, out var value) && value is InvocationExpressionSyntax registerInvocation) { if (DependencyProperty.TryGetRegisterCall(registerInvocation, context.SemanticModel, context.CancellationToken, out var registerMethod) || DependencyProperty.TryGetRegisterReadOnlyCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod) || DependencyProperty.TryGetRegisterAttachedCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod) || DependencyProperty.TryGetRegisterAttachedReadOnlyCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod)) { if (registerMethod.TryFindParameter(KnownSymbols.PropertyMetadata, out var registerParameter) && registerInvocation.TryFindArgument(registerParameter, out var registeredMetadataArg) && context.SemanticModel.TryGetType(metadataArg.Expression, context.CancellationToken, out var type) && context.SemanticModel.TryGetType(registeredMetadataArg.Expression, context.CancellationToken, out var registeredType) && !type.IsAssignableTo(registeredType, context.Compilation)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0017MetadataMustBeAssignable, metadataArg.GetLocation())); } } } else if (fieldOrProperty.Symbol == KnownSymbols.FrameworkElement.DefaultStyleKeyProperty && metadataArg.Expression is ObjectCreationExpressionSyntax metadataCreation) { if (!context.SemanticModel.TryGetSymbol(metadataCreation, KnownSymbols.FrameworkPropertyMetadata, context.CancellationToken, out _)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0017MetadataMustBeAssignable, metadataArg.GetLocation())); } else if (metadataCreation.TrySingleArgument(out var typeArg) && typeArg.Expression is TypeOfExpressionSyntax typeOf && typeOf.Type is IdentifierNameSyntax typeName && typeName.Identifier.ValueText != context.ContainingSymbol.ContainingType.MetadataName) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0018DefaultStyleKeyPropertyOverrideMetadataArgument, typeArg.GetLocation())); } } } }
private static void HandleInvocation(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } if (context.Node is InvocationExpressionSyntax invocation && !IsInObjectInitializer(invocation) && !IsInConstructor(invocation) && DependencyObject.TryGetSetValueCall(invocation, context.SemanticModel, context.CancellationToken, out _)) { var propertyArg = invocation.ArgumentList.Arguments[0]; if (!BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(propertyArg.Expression, context.CancellationToken), out var propertyMember) || propertyMember.Type == KnownSymbol.DependencyPropertyKey) { return; } if (propertyMember.Symbol is IFieldSymbol field && field == KnownSymbol.FrameworkElement.DataContextProperty) { return; } var clrProperty = context.ContainingProperty(); if (clrProperty.IsDependencyPropertyAccessor(context.SemanticModel, context.CancellationToken)) { return; } var clrMethod = context.ContainingSymbol as IMethodSymbol; if (ClrMethod.IsAttachedSet(clrMethod, context.SemanticModel, context.CancellationToken, out propertyMember)) { return; } if (IsCalleePotentiallyCreatedInScope(invocation.Expression as MemberAccessExpressionSyntax, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocation.GetLocation(), propertyMember, invocation.ArgumentList.Arguments[1])); } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is InvocationExpressionSyntax invocation && TryGetArgs(context, out var target, out var propertyArg, out var valueArg) && context.SemanticModel.TryGetSymbol(propertyArg.Expression, context.CancellationToken, out var symbol) && BackingFieldOrProperty.Match(symbol) is { } backing) { if (IsWrongType(backing, valueArg, context) is { } registeredType) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0014SetValueMustUseRegisteredType, valueArg.GetLocation(), target.Name, registeredType)); } if (backing.Type == KnownSymbols.DependencyProperty && backing.FindKey(context.SemanticModel, context.CancellationToken) is { } keyField) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0040SetUsingDependencyPropertyKey, propertyArg.GetLocation(), properties: ImmutableDictionary <string, string?> .Empty.Add(nameof(DependencyPropertyKeyType), keyField.Name), propertyArg, keyField.CreateArgument(context.SemanticModel, propertyArg.SpanStart))); } if (target == KnownSymbols.DependencyObject.SetCurrentValue && backing.Symbol is IFieldSymbol setField && (setField == KnownSymbols.FrameworkElement.DataContextProperty || setField.Name == "StyleProperty")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0043DoNotUseSetCurrentValue, invocation.GetLocation(), setField.Name, invocation.ArgumentList.Arguments[1])); } } }
private static void HandleInvocation(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is InvocationExpressionSyntax invocation && !IsInConstructor(invocation) && invocation.ArgumentList is ArgumentListSyntax argumentList && argumentList.Arguments.Count == 2 && argumentList.Arguments.TryElementAt(0, out var propertyArg) && DependencyObject.TryGetSetValueCall(invocation, context.SemanticModel, context.CancellationToken, out _) && BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(propertyArg.Expression, context.CancellationToken), out var backingFieldOrProperty) && !IsCalleePotentiallyCreatedInScope(invocation.Expression as MemberAccessExpressionSyntax, context.SemanticModel, context.CancellationToken)) { if (backingFieldOrProperty.Type == KnownSymbols.DependencyPropertyKey) { return; } if (backingFieldOrProperty.Symbol is IFieldSymbol field && field == KnownSymbols.FrameworkElement.DataContextProperty) { return; } var clrProperty = context.ContainingProperty(); if (clrProperty.IsDependencyPropertyAccessor(context.SemanticModel, context.CancellationToken)) { return; } var clrMethod = context.ContainingSymbol as IMethodSymbol; if (ClrMethod.IsAttachedSet(clrMethod, context.SemanticModel, context.CancellationToken, out backingFieldOrProperty)) { return; } context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0041SetMutableUsingSetCurrentValue, invocation.GetLocation(), backingFieldOrProperty, invocation.ArgumentList.Arguments[1])); } }
/// <summary> /// Get the backing fields for the <paramref name="property"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field. /// This method looks for fields that matches the name NameProperty and NamePropertyKey. /// </summary> private static bool TryGetBackingFieldsByName(IPropertySymbol property, Compilation compilation, out BackingFieldOrProperty getter, out BackingFieldOrProperty setter) { getter = default; setter = default; if (property == null || !property.ContainingType.IsAssignableTo(KnownSymbols.DependencyObject, compilation)) { return(false); } foreach (var member in property.ContainingType.GetMembers()) { if (BackingFieldOrProperty.TryCreateForDependencyProperty(member, out var candidate)) { if (candidate.Name.IsParts(property.Name, "Property")) { if (!DependencyProperty.IsPotentialDependencyPropertyBackingField(candidate)) { return(false); } getter = candidate; } if (candidate.Name.IsParts(property.Name, "PropertyKey")) { if (!DependencyProperty.IsPotentialDependencyPropertyKeyBackingField(candidate)) { return(false); } setter = candidate; } } } if (setter.Symbol == null) { setter = getter; } return(setter.Symbol != null); }
internal static bool TryGetRegisterInvocation(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax result, out IMethodSymbol symbol) { symbol = null; result = null; if (fieldOrProperty.TryGetAssignedValue(cancellationToken, out var value) && value is InvocationExpressionSyntax invocation) { if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out symbol) || TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out symbol) || TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out symbol) || TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out symbol)) { result = invocation; return(true); } } return(false); }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is InvocationExpressionSyntax invocation && TryGetArgs(context, out var target, out var propertyArg, out var valueArg) && context.SemanticModel.TryGetSymbol(propertyArg.Expression, context.CancellationToken, out ISymbol? symbol) && BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty)) { if (IsWrongType(fieldOrProperty, valueArg, context, out var registeredType)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0014SetValueMustUseRegisteredType, valueArg.GetLocation(), target.Name, registeredType)); } if (fieldOrProperty.Type == KnownSymbols.DependencyProperty && DependencyProperty.TryGetDependencyPropertyKeyFieldOrProperty(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var keyField)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0040SetUsingDependencyPropertyKey, propertyArg.GetLocation(), propertyArg, keyField.CreateArgument(context.SemanticModel, propertyArg.SpanStart))); } if (target == KnownSymbols.DependencyObject.SetCurrentValue && fieldOrProperty.Symbol is IFieldSymbol setField && setField == KnownSymbols.FrameworkElement.DataContextProperty) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0043DoNotUseSetCurrentValueForDataContext, invocation.GetLocation(), setField.Name, invocation.ArgumentList.Arguments[1])); } } }
internal static bool TryGetDependencyProperty(ObjectCreationExpressionSyntax objectCreation, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty fieldOrProperty) { fieldOrProperty = default; var invocation = objectCreation.FirstAncestorOrSelf <InvocationExpressionSyntax>(); if (invocation == null) { return(false); } if (DependencyProperty.TryGetRegisterCall(invocation, semanticModel, cancellationToken, out _) || DependencyProperty.TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out _) || DependencyProperty.TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out _) || DependencyProperty.TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out _)) { if (objectCreation.TryFirstAncestor <FieldDeclarationSyntax>(out var fieldDeclaration) && semanticModel.TryGetSymbol(fieldDeclaration, cancellationToken, out var field)) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(field, out fieldOrProperty)); } if (objectCreation.TryFirstAncestor <PropertyDeclarationSyntax>(out var propertyDeclaration) && semanticModel.TryGetSymbol(propertyDeclaration, cancellationToken, out var property)) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(property, out fieldOrProperty)); } return(false); } if (invocation.Expression is MemberAccessExpressionSyntax memberAccess && (DependencyProperty.TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) || DependencyProperty.TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _)) && semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out ISymbol? candidate)) { return(BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out fieldOrProperty)); } return(false); }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MemberDeclarationSyntax memberDeclaration && FieldOrProperty.TryCreate(context.ContainingSymbol, out var fieldOrProperty) && fieldOrProperty.Type == KnownSymbol.RoutedEvent) { if (RoutedEvent.TryGetRegisteredName(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredName) && !fieldOrProperty.Name.IsParts(registeredName, "Event")) { context.ReportDiagnostic( Diagnostic.Create( WPF0100BackingFieldShouldMatchRegisteredName.Descriptor, FindIdentifier(context.Node).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Event"), fieldOrProperty.Name, registeredName)); } if (RoutedEvent.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var typeArg, out var registeredOwnerType) && !Equals(registeredOwnerType, context.ContainingSymbol.ContainingType)) { context.ReportDiagnostic( Diagnostic.Create( WPF0101RegisterContainingTypeAsOwner.Descriptor, typeArg.GetLocation(), fieldOrProperty.ContainingType.Name, registeredName)); } if (!fieldOrProperty.IsStaticReadOnly()) { context.ReportDiagnostic( Diagnostic.Create( WPF0107BackingMemberShouldBeStaticReadonly.Descriptor, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation())); } } }
/// <summary> /// Get the backing fields for the <paramref name="property"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field. /// </summary> private static bool TryGetBackingFields(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty getField, out BackingFieldOrProperty setField) { getField = default; setField = default; if (property.IsPotentialClrProperty(semanticModel.Compilation) && property.TrySingleDeclaration(cancellationToken, out PropertyDeclarationSyntax propertyDeclaration) && TryGetBackingFields(propertyDeclaration, semanticModel, cancellationToken, out getField, out setField)) { if (getField.ContainingType.IsGenericType) { return(property.ContainingType.TryFindFirstMember(getField.Name, out var getMember) && BackingFieldOrProperty.TryCreateForDependencyProperty(getMember, out getField) && property.ContainingType.TryFindFirstMember(setField.Name, out var setMember) && BackingFieldOrProperty.TryCreateForDependencyProperty(setMember, out setField)); } return(true); } return(false); }
private static bool IsWrongType(BackingFieldOrProperty fieldOrProperty, ArgumentSyntax argument, SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out ITypeSymbol?registeredType) { if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out registeredType) && !PropertyMetadata.IsValueValidForRegisteredType(argument.Expression, registeredType, context.SemanticModel, context.CancellationToken)) { if (context.SemanticModel.TryGetType(argument.Expression, context.CancellationToken, out var type)) { if (type == KnownSymbols.Object) { return(false); } if (registeredType.IsAssignableTo(KnownSymbols.Freezable, context.Compilation) && type.IsAssignableTo(KnownSymbols.Freezable, context.Compilation)) { return(false); } } return(true); } return(false); }
private static bool IsWrongType(BackingFieldOrProperty fieldOrProperty, ArgumentSyntax argument, SyntaxNodeAnalysisContext context, out ITypeSymbol registeredType) { if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out registeredType) && !context.SemanticModel.IsRepresentationPreservingConversion(argument.Expression, registeredType, context.CancellationToken)) { if (context.SemanticModel.TryGetType(argument.Expression, context.CancellationToken, out var type)) { if (type == KnownSymbol.Object) { return(false); } if (registeredType.IsAssignableTo(KnownSymbol.Freezable, context.Compilation) && type.IsAssignableTo(KnownSymbol.Freezable, context.Compilation)) { return(false); } } return(true); } return(false); }
internal static bool TryGetRegisteredName(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out string result) { result = null; if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out _)) { return(invocation.TryGetArgumentAtIndex(0, out var arg) && arg.TryGetStringValue(semanticModel, cancellationToken, out result)); } if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) && !source.Symbol.Equals(backing.Symbol)) { return(TryGetRegisteredName(source, semanticModel, cancellationToken, out result)); } if (backing.Symbol.Locations.All(x => !x.IsInSource) && TryGetPropertyByName(backing, out var property)) { result = property.Name; return(true); } return(false); }