EntityFiledAccessCodeFixProvider.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System.Collections.Immutable;
  2. using System.Composition;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Microsoft.CodeAnalysis;
  7. using Microsoft.CodeAnalysis.CodeActions;
  8. using Microsoft.CodeAnalysis.CodeFixes;
  9. using Microsoft.CodeAnalysis.CSharp;
  10. using Microsoft.CodeAnalysis.CSharp.Syntax;
  11. using Microsoft.CodeAnalysis.Formatting;
  12. namespace ET.Analyzer
  13. {
  14. [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(EntityFiledAccessCodeFixProvider)), Shared]
  15. public class EntityFiledAccessCodeFixProvider: CodeFixProvider
  16. {
  17. public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(DiagnosticIds.EntityFiledAccessAnalyzerRuleId);
  18. public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
  19. public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
  20. {
  21. SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
  22. Diagnostic diagnostic = context.Diagnostics.First();
  23. Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
  24. // 获取diagnostic 传递来的 FriendOfType 值
  25. diagnostic.Properties.TryGetValue("FriendOfType", out string? frienClassType);
  26. if (frienClassType==null)
  27. {
  28. return;
  29. }
  30. ClassDeclarationSyntax? classDeclaration = root?.FindToken(diagnosticSpan.Start).Parent?.AncestorsAndSelf().OfType<ClassDeclarationSyntax>().First();
  31. // 构造Code Action
  32. CodeAction action = CodeAction.Create(
  33. "Add FriendOf Attribute",
  34. c => AddFriendOfAttributeAsync(context.Document, classDeclaration,frienClassType, c),
  35. equivalenceKey: nameof(EntityFiledAccessCodeFixProvider));
  36. // 注册codeFix Code Action
  37. context.RegisterCodeFix(action, diagnostic);
  38. }
  39. private static async Task<Document> AddFriendOfAttributeAsync(Document document, ClassDeclarationSyntax? classDeclaration, string friendOfType, CancellationToken cancellationToken)
  40. {
  41. // 构造FriendOfAttribute 语法节点
  42. AttributeArgumentSyntax attributeArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseTypeName(friendOfType)));
  43. AttributeSyntax attributeSyntax = SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("FriendOfAttribute"))
  44. .WithArgumentList(SyntaxFactory.AttributeArgumentList(SyntaxFactory.SingletonSeparatedList(attributeArgument)));
  45. // 构造添加构造FriendOfAttribute 得AttributeList语法节点
  46. SyntaxList<AttributeListSyntax>? attributes = classDeclaration?.AttributeLists.Add(
  47. SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attributeSyntax)).NormalizeWhitespace());
  48. if (attributes == null)
  49. {
  50. return document;
  51. }
  52. // 构造替换AttributeList的 ClassDeclaration语法节点
  53. ClassDeclarationSyntax? newClassDeclaration = classDeclaration?.WithAttributeLists(attributes.Value).WithAdditionalAnnotations(Formatter.Annotation);
  54. SyntaxNode? root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
  55. if (root==null ||classDeclaration==null || newClassDeclaration==null )
  56. {
  57. return document;
  58. }
  59. // 构造替换classDeclaration的root语法节点
  60. var newRoot = root.ReplaceNode(classDeclaration, newClassDeclaration);
  61. // 替换root语法节点
  62. return document.WithSyntaxRoot(newRoot);
  63. }
  64. }
  65. }