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) { if (syntaxRoot.TryFindNodeOrAncestor <ClassDeclarationSyntax>(diagnostic, out var classDeclaration)) { if (ValueConverter.TryGetConversionTypes(classDeclaration, semanticModel, context.CancellationToken, out var sourceType, out var targetType)) { context.RegisterCodeFix( $"Add [ValueConversion(typeof({sourceType}), typeof({targetType}))].", (e, _) => AddAttribute(e, classDeclaration, sourceType, targetType), $"Add [ValueConversion(typeof({sourceType}), typeof({targetType}))].", diagnostic); } else { context.RegisterCodeFix( $"Add [ValueConversion(typeof({sourceType?.ToString() ?? "TYPE"}), typeof({targetType?.ToString() ?? "TYPE"}))].", (e, _) => AddAttribute(e, classDeclaration, sourceType, targetType), $"Add [ValueConversion(typeof({sourceType?.ToString() ?? "TYPE"}), typeof({targetType?.ToString() ?? "TYPE"}))].", diagnostic); } } }
/// <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; } var argument = syntaxRoot.FindNode(diagnostic.Location.SourceSpan) .FirstAncestorOrSelf <AttributeArgumentSyntax>(); var attribute = argument.FirstAncestor <AttributeSyntax>(); if (ValueConverter.TryGetConversionTypes( attribute.FirstAncestor <ClassDeclarationSyntax>(), semanticModel, context.CancellationToken, out var sourceType, out var targetType)) { context.RegisterCodeFix( $"Change to [ValueConversion(typeof({sourceType}), typeof({targetType}))].", (e, _) => FixArgument(e, attribute, sourceType, targetType), $"Change to [ValueConversion(typeof({sourceType}), typeof({targetType}))].", diagnostic); } } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.ContainingSymbol is INamedTypeSymbol { IsAbstract : false, IsStatic : false } type&& type.IsAssignableToEither(KnownSymbols.IValueConverter, KnownSymbols.IMultiValueConverter, context.SemanticModel.Compilation) && context.Node is ClassDeclarationSyntax classDeclaration && type.DeclaredAccessibility != Accessibility.Private && type.DeclaredAccessibility != Accessibility.Protected) { if (!type.IsAssignableTo(KnownSymbols.MarkupExtension, context.SemanticModel.Compilation)) { if (ValueConverter.TryGetDefaultFieldsOrProperties(type, context.SemanticModel.Compilation, out var defaults)) { foreach (var fieldOrProperty in defaults) { if (fieldOrProperty.Value(context.CancellationToken) is { } assignedValue&& context.SemanticModel.TryGetType(assignedValue, context.CancellationToken, out var assignedType) && !TypeSymbolComparer.Equal(assignedType, type)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0074DefaultMemberOfWrongType, assignedValue.GetLocation())); } } } else if (!Virtual.HasVirtualOrAbstractOrProtectedMembers(type) && !type.Constructors.TryFirst(x => x.Parameters.Length > 0, out _) && !Mutable.HasMutableInstanceMembers(type) && !classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0070ConverterDoesNotHaveDefaultField, classDeclaration.Identifier.GetLocation())); } } if (type.IsAssignableTo(KnownSymbols.IValueConverter, context.SemanticModel.Compilation)) { if (Attribute.TryFind(classDeclaration, KnownSymbols.ValueConversionAttribute, context.SemanticModel, context.CancellationToken, out var attribute)) { if (ValueConverter.TryGetConversionTypes(classDeclaration, context.SemanticModel, context.CancellationToken, out var sourceType, out var targetType)) { if (sourceType is { } &&
/// <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) { if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out AttributeSyntax? attribute) && attribute.TryFirstAncestor(out ClassDeclarationSyntax? classDeclaration) && ValueConverter.TryGetConversionTypes(classDeclaration, semanticModel, context.CancellationToken, out var sourceType, out var targetType)) { context.RegisterCodeFix( $"[ValueConversion(typeof({sourceType}), typeof({targetType}))].", (e, _) => FixArgument(e, attribute, sourceType, targetType), $"[ValueConversion(typeof({sourceType}), typeof({targetType}))].", diagnostic); } } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.ContainingSymbol is INamedTypeSymbol type && type.IsAssignableToEither(KnownSymbols.IValueConverter, KnownSymbols.IMultiValueConverter, context.Compilation) && context.Node is ClassDeclarationSyntax classDeclaration && !type.IsAbstract && type.DeclaredAccessibility != Accessibility.Private && type.DeclaredAccessibility != Accessibility.Protected) { if (!type.IsAssignableTo(KnownSymbols.MarkupExtension, context.Compilation)) { if (ValueConverter.TryGetDefaultFieldsOrProperties(type, context.Compilation, out var defaults)) { foreach (var fieldOrProperty in defaults) { if (fieldOrProperty.TryGetAssignedValue(context.CancellationToken, out var assignedValue) && context.SemanticModel.TryGetType(assignedValue, context.CancellationToken, out var assignedType) && !Equals(assignedType, type)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0074DefaultMemberOfWrongType, assignedValue.GetLocation())); } } } else if (!Virtual.HasVirtualOrAbstractOrProtectedMembers(type) && !type.Constructors.TryFirst(x => x.Parameters.Length > 0, out _) && !Mutable.HasMutableInstanceMembers(type)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0070ConverterDoesNotHaveDefaultField, classDeclaration.Identifier.GetLocation())); } } if (type.IsAssignableTo(KnownSymbols.IValueConverter, context.Compilation)) { if (Attribute.TryFind(classDeclaration, KnownSymbols.ValueConversionAttribute, context.SemanticModel, context.CancellationToken, out var attribute)) { if (ValueConverter.TryGetConversionTypes(classDeclaration, context.SemanticModel, context.CancellationToken, out var sourceType, out var targetType)) { if (sourceType != null && sourceType != QualifiedType.System.Object && attribute.TryFindArgument(0, "sourceType", out var arg) && arg.Expression is TypeOfExpressionSyntax sourceTypeOf && TypeOf.TryGetType(sourceTypeOf, type, context.SemanticModel, context.CancellationToken, out var argType) && !Equals(argType, sourceType)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0072ValueConversionMustUseCorrectTypes, arg.GetLocation(), sourceType)); } if (attribute.TryFindArgument(1, "targetType", out arg) && arg.Expression is TypeOfExpressionSyntax targetTypeOf && TypeOf.TryGetType(targetTypeOf, type, context.SemanticModel, context.CancellationToken, out argType) && !Equals(argType, targetType)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0072ValueConversionMustUseCorrectTypes, arg.GetLocation(), targetType)); } } } else { if (ValueConverter.TryGetConversionTypes(classDeclaration, context.SemanticModel, context.CancellationToken, out _, out _)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0071ConverterDoesNotHaveAttribute, classDeclaration.Identifier.GetLocation())); } else { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0073ConverterDoesNotHaveAttributeUnknownTypes, classDeclaration.Identifier.GetLocation())); } } } } }