Просмотр исходного кода

* 添加FriendClassAttribute 代码补全 (#347)

alt enter 回车 自动添加报错对应的FriendClassAttribute
tanghai 3 лет назад
Родитель
Сommit
d28df3ce4c

+ 3 - 1
Share/Analyzer/Analyzer/EntityFiledAccessAnalyzer.cs

@@ -114,7 +114,9 @@ namespace ET.Analyzer
                 return;
             }
 
-            Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax.GetLocation(), filedSymbol.ContainingType.Name,
+            var builder = ImmutableDictionary.CreateBuilder<string, string?>();
+            builder.Add("FriendClassType",filedSymbol.ContainingType.ToString());
+            Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax.GetLocation(), builder.ToImmutable(),filedSymbol.ContainingType.ToString(),
                 filedSymbol.Name);
             context.ReportDiagnostic(diagnostic);
         }

+ 78 - 0
Share/Analyzer/CodeFixer/EntityFiledAccessCodeFixProvider.cs

@@ -0,0 +1,78 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+
+namespace ET.Analyzer
+{
+    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(EntityFiledAccessCodeFixProvider)), Shared]
+    public class EntityFiledAccessCodeFixProvider: CodeFixProvider
+    {
+        public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(DiagnosticIds.EntityFiledAccessAnalyzerRuleId);
+        
+        public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+        
+        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+        {
+            SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+            
+            Diagnostic diagnostic = context.Diagnostics.First();
+
+            Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
+            // 获取diagnostic 传递来的 FriendClassType 值
+            diagnostic.Properties.TryGetValue("FriendClassType", out string? frienClassType);
+            if (frienClassType==null)
+            {
+                return;
+            }
+            
+            ClassDeclarationSyntax? classDeclaration = root?.FindToken(diagnosticSpan.Start).Parent?.AncestorsAndSelf().OfType<ClassDeclarationSyntax>().First();
+            // 构造Code Action
+            CodeAction action = CodeAction.Create(
+                "Add FriendClass Attribute",
+                c => AddFriendClassAttributeAsync(context.Document, classDeclaration,frienClassType, c),
+                equivalenceKey: nameof(EntityFiledAccessCodeFixProvider));
+
+            // 注册codeFix Code Action
+            context.RegisterCodeFix(action, diagnostic);
+        }
+
+
+        private static async Task<Document> AddFriendClassAttributeAsync(Document document, ClassDeclarationSyntax? classDeclaration, string friendClassType, CancellationToken cancellationToken)
+        {
+            // 构造FriendClassAttribute 语法节点
+            AttributeArgumentSyntax attributeArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseTypeName(friendClassType)));
+            AttributeSyntax attributeSyntax = SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("FriendClassAttribute"))
+                    .WithArgumentList(SyntaxFactory.AttributeArgumentList(SyntaxFactory.SingletonSeparatedList(attributeArgument)));
+            // 构造添加构造FriendClassAttribute 得AttributeList语法节点
+            SyntaxList<AttributeListSyntax>? attributes = classDeclaration?.AttributeLists.Add(
+                SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attributeSyntax)).NormalizeWhitespace());
+
+            if (attributes == null)
+            {
+                return document;
+            }
+            // 构造替换AttributeList的 ClassDeclaration语法节点
+            ClassDeclarationSyntax? newClassDeclaration =  classDeclaration?.WithAttributeLists(attributes.Value).WithAdditionalAnnotations(Formatter.Annotation);
+
+            SyntaxNode? root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+
+            if (root==null ||classDeclaration==null || newClassDeclaration==null )
+            {
+                return document;
+            }
+            // 构造替换classDeclaration的root语法节点
+            var newRoot = root.ReplaceNode(classDeclaration, newClassDeclaration);
+            
+            // 替换root语法节点
+            return document.WithSyntaxRoot(newRoot);
+        }
+    }
+}