public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MarkOperatorAsPublicAndStatic)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } ModifierListInfo info = SyntaxInfo.ModifierListInfo(memberDeclaration); var title = "Add "; if (info.ExplicitAccessibility == Accessibility.Public) { title += "modifier 'static'"; } else if (info.IsStatic) { title += "modifier 'public'"; } else { title += "modifiers 'public static'"; } CodeAction codeAction = CodeAction.Create( title, cancellationToken => { SyntaxNode newNode = memberDeclaration; if (info.Modifiers.ContainsAny(SyntaxKind.InternalKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.PrivateKeyword)) { newNode = SyntaxAccessibility.WithoutExplicitAccessibility(newNode); } if (!info.Modifiers.Contains(SyntaxKind.PublicKeyword)) { newNode = ModifierList.Insert(newNode, SyntaxKind.PublicKeyword); } if (!info.IsStatic) { newNode = ModifierList.Insert(newNode, SyntaxKind.StaticKeyword); } return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, cancellationToken)); }, base.GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.FormatDeclarationBraces: { CodeAction codeAction = CodeAction.Create( "Format braces", cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantOverridingMember: { CodeAction codeAction = CodeAction.Create( $"Remove {CSharpFacts.GetTitle(memberDeclaration)}", cancellationToken => context.Document.RemoveMemberAsync(memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddDefaultAccessModifier: { var accessibility = (Accessibility)Enum.Parse( typeof(Accessibility), diagnostic.Properties[nameof(Accessibility)]); CodeAction codeAction = CodeAction.Create( "Add default access modifier", cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantSealedModifier: { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword); break; } case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration: { CodeAction codeAction = CodeAction.Create( "Remove unnecessary semicolon", cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ReorderModifiers: { CodeAction codeAction = CodeAction.Create( "Reorder modifiers", cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.MarkFieldAsReadOnly: { var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration; SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables; string title = (declarators.Count == 1) ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only" : "Mark fields as read-only"; ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title); break; } case DiagnosticIdentifiers.UseConstantInsteadOfField: { CodeAction codeAction = CodeAction.Create( "Use constant instead of field", cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseReadOnlyAutoProperty: { CodeAction codeAction = CodeAction.Create( "Use read-only auto-property", cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ReplaceCommentWithDocumentationComment: { CodeAction codeAction = CodeAction.Create( ReplaceCommentWithDocumentationCommentRefactoring.Title, cancellationToken => ReplaceCommentWithDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.MakeMethodExtensionMethod: { var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Make method an extension method", cancellationToken => { ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0]; ParameterSyntax newParameter = ModifierList.Insert(parameter, SyntaxKind.ThisKeyword); return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.RemoveRedundantOverridingMember: { CodeAction codeAction = CodeActionFactory.RemoveMemberDeclaration(context.Document, memberDeclaration, equivalenceKey: GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddAccessibilityModifiersOrViceVersa: { if (diagnostic.Properties.TryGetValue(nameof(Accessibility), out string accessibilityText)) { var accessibility = (Accessibility)Enum.Parse(typeof(Accessibility), accessibilityText); CodeAction codeAction = CodeAction.Create( "Add accessibility modifiers", ct => { MemberDeclarationSyntax newNode = SyntaxAccessibility.WithExplicitAccessibility(memberDeclaration, accessibility); return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( "Remove accessibility modifiers", ct => { MemberDeclarationSyntax newNode = SyntaxAccessibility.WithoutExplicitAccessibility(memberDeclaration); return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case DiagnosticIdentifiers.RemoveRedundantSealedModifier: { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword); break; } case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration: { CodeAction codeAction = CodeAction.Create( "Remove unnecessary semicolon", cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.OrderModifiers: { CodeAction codeAction = CodeAction.Create( "Order modifiers", ct => OrderModifiersAsync(context.Document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.MakeFieldReadOnly: { var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration; SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables; string title = (declarators.Count == 1) ? $"Make '{declarators[0].Identifier.ValueText}' read-only" : "Make fields read-only"; ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title); break; } case DiagnosticIdentifiers.UseConstantInsteadOfField: { CodeAction codeAction = CodeAction.Create( "Use constant instead of field", cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseReadOnlyAutoProperty: { CodeAction codeAction = CodeAction.Create( "Use read-only auto-property", cancellationToken => UseReadOnlyAutoPropertyAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ConvertCommentToDocumentationComment: { CodeAction codeAction = CodeAction.Create( ConvertCommentToDocumentationCommentRefactoring.Title, cancellationToken => ConvertCommentToDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.MakeMethodExtensionMethod: { var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Make method an extension method", cancellationToken => { ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0]; ParameterSyntax newParameter = ModifierList.Insert(parameter, SyntaxKind.ThisKeyword); return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
/// <summary> /// Creates a new <see cref="ModifierListInfo"/> with accessibility modifiers updated. /// </summary> /// <param name="newAccessibility"></param> /// <param name="comparer"></param> /// <returns></returns> public ModifierListInfo WithExplicitAccessibility(Accessibility newAccessibility, IComparer <SyntaxKind> comparer = null) { ThrowInvalidOperationIfNotInitialized(); Accessibility accessibility = ExplicitAccessibility; if (accessibility == newAccessibility) { return(this); } comparer = comparer ?? ModifierKindComparer.Default; SyntaxNode declaration = Parent; if (accessibility.IsSingleTokenAccessibility() && newAccessibility.IsSingleTokenAccessibility()) { int insertIndex = ModifierList.GetInsertIndex(Modifiers, GetTokenKind(), comparer); int tokenIndex = GetFirstTokenIndex(); if (tokenIndex == insertIndex || tokenIndex == insertIndex - 1) { SyntaxToken token = Modifiers[tokenIndex]; SyntaxToken newToken = SyntaxFactory.Token(GetTokenKind()).WithTriviaFrom(token); SyntaxTokenList newModifiers = Modifiers.Replace(token, newToken); return(WithModifiers(newModifiers)); } } if (accessibility != Accessibility.NotApplicable) { (int tokenIndex, int secondTokenIndex) = GetTokenIndexes(); declaration = ModifierList.RemoveAt(declaration, Math.Max(tokenIndex, secondTokenIndex)); if (secondTokenIndex != -1) { declaration = ModifierList.RemoveAt(declaration, Math.Min(tokenIndex, secondTokenIndex)); } } if (newAccessibility != Accessibility.NotApplicable) { declaration = ModifierList.Insert(declaration, newAccessibility, comparer); } return(SyntaxInfo.ModifierListInfo(declaration)); SyntaxKind GetTokenKind() { switch (newAccessibility) { case Accessibility.Private: return(SyntaxKind.PrivateKeyword); case Accessibility.Protected: return(SyntaxKind.ProtectedKeyword); case Accessibility.Internal: return(SyntaxKind.InternalKeyword); case Accessibility.Public: return(SyntaxKind.PublicKeyword); case Accessibility.NotApplicable: return(SyntaxKind.None); default: throw new ArgumentException("", nameof(newAccessibility)); } } }