private static Fix CreateFix( SyntaxGenerator syntaxGenerator, PropertyDeclarationSyntax propertyDeclaration, IPropertySymbol property, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken, ImmutableDictionary <string, ReportDiagnostic> diagnosticOptions) { string backingFieldName; if (Property.IsMutableAutoProperty(propertyDeclaration)) { backingFieldName = MakePropertyNotifyHelper.BackingFieldNameForAutoProperty(propertyDeclaration); var backingField = (FieldDeclarationSyntax)syntaxGenerator.FieldDeclaration( backingFieldName, propertyDeclaration.Type, Accessibility.Private, DeclarationModifiers.None); var notifyingProperty = propertyDeclaration.WithGetterReturningBackingField( syntaxGenerator, backingFieldName) .WithNotifyingSetter( property, syntaxGenerator, backingFieldName, invoker, diagnosticOptions); return(new Fix(propertyDeclaration, notifyingProperty, backingField)); } if (IsSimpleAssignmentOnly( propertyDeclaration, semanticModel, cancellationToken, out ExpressionStatementSyntax assignStatement, out backingFieldName)) { var notifyingProperty = propertyDeclaration.WithGetterReturningBackingField( syntaxGenerator, backingFieldName) .WithNotifyingSetter( property, syntaxGenerator, assignStatement, backingFieldName, invoker, diagnosticOptions); return(new Fix(propertyDeclaration, notifyingProperty, null)); } return(new Fix(propertyDeclaration, null, null)); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken) .ConfigureAwait(false); var semanticModel = await context.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 ifStatement = syntaxRoot.FindNode(diagnostic.Location.SourceSpan) .FirstAncestorOrSelf <IfStatementSyntax>(); if (!IsIfReturn(ifStatement)) { continue; } var setter = ifStatement.FirstAncestorOrSelf <AccessorDeclarationSyntax>(); if (setter?.IsKind(SyntaxKind.SetAccessorDeclaration) != true) { continue; } var propertyDeclaration = setter.FirstAncestorOrSelf <PropertyDeclarationSyntax>(); var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, context.CancellationToken); if (property == null) { continue; } if (!Property.TryGetBackingField(property, semanticModel, context.CancellationToken, out IFieldSymbol backingField)) { continue; } if (Property.TryFindValue(setter, semanticModel, context.CancellationToken, out IParameterSymbol value) && CanFix(ifStatement, semanticModel, context.CancellationToken, value, backingField, property)) { var syntaxGenerator = SyntaxGenerator.GetGenerator(context.Document); var fieldAccess = backingField.Name.StartsWith("_") ? backingField.Name : $"this.{backingField.Name}"; var referenceTypeEquality = MakePropertyNotifyHelper.ReferenceTypeEquality(context.Document.Project.CompilationOptions.SpecificDiagnosticOptions); var equalsExpression = (ExpressionSyntax)syntaxGenerator.InvocationExpression( referenceTypeEquality, SyntaxFactory.ParseName("value"), SyntaxFactory.ParseExpression(fieldAccess)); context.RegisterCodeFix( CodeAction.Create( $"Use {referenceTypeEquality}", cancellationToken => Task.FromResult(context.Document.WithSyntaxRoot(syntaxRoot.ReplaceNode(ifStatement.Condition, equalsExpression))), this.GetType().FullName), diagnostic); } } }