C# Roslyn 更改注释类型

Posted

技术标签:

【中文标题】C# Roslyn 更改注释类型【英文标题】:C# Roslyn change type of comment 【发布时间】:2014-06-06 09:30:00 【问题描述】:

我正在尝试对 Visual Studio 进行扩展,以更改代码中的某些语法。 实际上,我已经完成了第一步,如果变量的名称不符合我们在公司中使用的规则,则更改该变量的名称。例如:

int newVariable;
double test;

将改为:

int iNewVariable;
double dblTest;

现在我必须更改这种类型的评论:(SingleLineComment)

//this is a single line Comment

进入多行注释

/*Here it's a MultiLine one*/

我使用 Roslyn Syntax Visualiser 来查找类型和种类以制作正确的代码,但没有任何效果。 这是我为诊断所做的:

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace CodeFix

    [DiagnosticAnalyzer]
    [ExportDiagnosticAnalyzer(DiagnosticId, LanguageNames.CSharp)]
    public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer<SyntaxKind>
    
        internal const string DiagnosticId = "CodeFix";
        internal const string Description = "Mauvais formattage";
        internal const string MessageFormat = "'0'";
        internal const string Category = "Correction";

        internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Warning);

        public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        
            get  return ImmutableArray.Create(Rule); 
        
        public ImmutableArray<SyntaxKind> SyntaxKindsOfInterest //Ce qui nous intéresse
        
            get
            
                return ImmutableArray.Create(SyntaxKind.IfStatement, SyntaxKind.ElseClause, SyntaxKind.LocalDeclarationStatement, SyntaxKind.ConstKeyword, SyntaxKind.SingleLineCommentTrivia, SyntaxKind.SimpleAssignmentExpression);
            
        
        public void AnalyzeNode(SyntaxNode node, SemanticModel model, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) //Analyse des Nodes
        

            var ifStatement = node as IfStatementSyntax; //Récupération des IfStatement parmis tous les nodes
            if (ifStatement != null &&
                ifStatement.Statement != null &&
                !ifStatement.Statement.IsKind(SyntaxKind.Block))
            
                addDiagnostic(Diagnostic.Create(Rule, ifStatement.IfKeyword.GetLocation(), "Le if require des crochets"));
            

            var elseClause = node as ElseClauseSyntax; //Récupération des Else parmis tous les nodes
            if (elseClause != null &&
                elseClause.Statement != null &&
                !elseClause.Statement.IsKind(SyntaxKind.Block) && //Pas que ce soit déjà un block avec 
                !elseClause.Statement.IsKind(SyntaxKind.IfStatement)) //A cause des else if
            
                addDiagnostic(Diagnostic.Create(Rule, elseClause.ElseKeyword.GetLocation(), "le else require des crochets"));
            

        
    
    internal class IDiagnosticAnalyzer : ISyntaxTreeAnalyzer
    
        internal const string DiagnosticIdComment = "CommentChanger";
        internal const string DescriptionComment = "Les commentaires doivent être en format /* */";
        internal const string MessageFormatComment = "'0' doit être en multiline";
        internal const string CategoryComment = "Renommage";

        internal static DiagnosticDescriptor RuleComment = new DiagnosticDescriptor(DiagnosticIdComment, DescriptionComment, MessageFormatComment, CategoryComment, DiagnosticSeverity.Warning);

        public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        
            get  return ImmutableArray.Create(RuleComment); 
        

        public void AnalyzeSyntaxTree(SyntaxTree tree, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken)
        
            var root = tree.GetRoot();
            var trivia = root.DescendantTrivia();
            var a = trivia.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia)).ToList();

            foreach (var b in a)
            
                addDiagnostic(Diagnostic.Create(RuleComment, b.GetLocation(), "Commentaire sur une ligne"));
            
        
    


这里是代码修复:

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Formatting;
using System;

namespace CodeFix

    [ExportCodeFixProvider(DiagnosticAnalyzer.DiagnosticId, LanguageNames.CSharp)]
    internal class CodeFixProvider : ICodeFixProvider
    
        public IEnumerable<string> GetFixableDiagnosticIds()
        
            return new[]  DiagnosticAnalyzer.DiagnosticId ;
        

        public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
        
            var root = await document.GetSyntaxRootAsync(cancellationToken); //Document à utiliser (root)
            var token = root.FindToken(span.Start); //


            if (token.IsKind(SyntaxKind.IfKeyword))
            
                var ifStatement = (IfStatementSyntax)token.Parent;
                var newIfStatement = ifStatement
                    .WithStatement(SyntaxFactory.Block(ifStatement.Statement))
                    .WithAdditionalAnnotations(Formatter.Annotation); //Pour que ce soit indenté juste

                var newRoot = root.ReplaceNode(ifStatement, newIfStatement); 

                return new[]  CodeAction.Create("Ajouter des crochets", document.WithSyntaxRoot(newRoot)) ;
            

            if (token.IsKind(SyntaxKind.ElseKeyword))
            
                var elseClause = (ElseClauseSyntax)token.Parent;
                var newElseClause = elseClause
                    .WithStatement(SyntaxFactory.Block(elseClause.Statement))
                    .WithAdditionalAnnotations(Formatter.Annotation);

                var newRoot = root.ReplaceNode(elseClause, newElseClause);

                return new[]  CodeAction.Create("Ajouter des crochets", document.WithSyntaxRoot(newRoot)) ;
            

            if (token.IsKind(SyntaxKind.SingleLineCommentTrivia))
            

                var root1 = await document.GetSyntaxRootAsync(cancellationToken);
                var token1 = root1.FindToken(span.Start);
                var allTrivia = token1.GetAllTrivia();
                foreach (var singleTrivia in allTrivia)
                
                    if (singleTrivia.IsKind(SyntaxKind.SingleLineCommentTrivia))
                    
                        var commentContent = singleTrivia.ToString().Replace("//", string.Empty);
                        var newComment = SyntaxFactory.Comment(string.Format("/*0*/", commentContent));
                        var newRoot = root.ReplaceTrivia(singleTrivia, newComment);
                        return new[]  CodeAction.Create("Convert to multiline", document.WithSyntaxRoot(newRoot)) ;
                    
                

                

            return null;
            
    


用户必须点击我的程序给出的广告,评论才会改变。

但我的程序永远不会进入我必须调用该方法的地方。

我正在与 Roslyn 一起迈出第一步,所以我还不知道很多东西,但我正在学习它..

编辑:

添加的所有代码

【问题讨论】:

【参考方案1】:

我整理了一个使用 CodeFix 和诊断的示例,该示例将单行 cmets 替换为多行 cmets。这是一些代码。其中很多是基于 Dustin Campbell 的来自 Build 的 Roslyn 演示,可以在 http://channel9.msdn.com/Events/Build/2014/2-577 看到。

从 ISyntaxTreeAnalyzer 实现分析语法树以查找单行 cmets:

[DiagnosticAnalyzer]
[ExportDiagnosticAnalyzer(DiagnosticId, LanguageNames.CSharp)]
internal class DiagnosticAnalyzer : ISyntaxTreeAnalyzer

    internal const string DiagnosticId = "CommentChanger";
    internal const string Description = "Single comments should be multiline comments";
    internal const string MessageFormat = "'0' should be multiline";
    internal const string Category = "Naming";

    internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Warning);

    public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
    
        get  return ImmutableArray.Create(Rule); 
    

    public void AnalyzeSyntaxTree(SyntaxTree tree, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken)
    
        var root = tree.GetRoot();
        var trivia = root.DescendantTrivia();
        var a = trivia.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia)).ToList();

        foreach(var b in a)
        
            addDiagnostic(Diagnostic.Create(Rule, b.GetLocation(), "Single comment"));
        
    

来自 ICodeFixProvider 的 GetFixesAsync 实现:

public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
    
        var root = await document.GetSyntaxRootAsync(cancellationToken);
        var token = root.FindToken(span.Start);
        var allTrivia = token.GetAllTrivia();
        foreach(var singleTrivia in allTrivia)
        
            if (singleTrivia.IsKind(SyntaxKind.SingleLineCommentTrivia))
            
                var commentContent = singleTrivia.ToString().Replace("//", string.Empty);
                var newComment = SyntaxFactory.Comment(string.Format("/*0*/", commentContent));
                var newRoot = root.ReplaceTrivia(singleTrivia, newComment);
                return new[]  CodeAction.Create("Convert to multiline", document.WithSyntaxRoot(newRoot)) ;
            
                   
        return null;
    

【讨论】:

谢谢!但我有一个问题。让我将代码放在: public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer 或像这样的其他类中 public class IDiagnosticAnalyzer : ISyntaxTreeAnalyzer 抱歉回复缓慢。此示例使用 ISyntaxTreeAnalyzer - 我已将类的其余代码添加到上面。你会发现 AnaylzeSyntaxTree 方法是由 ISyntaxTreeAnalyzer 接口实现的 所以,这就是我已经尝试过的......但也许在 DiagnosticAnalyzer 中有 2 个类是一个问题?因为我没有任何诊断......即使我拿你的代码,同样的,复制粘贴。没有错误,但没有诊断。唯一的区别是我的 DiagnosticAnalyzer.cs 中有另一个类,用于分析某些节点: public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer 我会尝试为这两个类使用两个单独的文件。另外,如果您发布所有代码,我会看看为什么这两个类会发生冲突 我已将您的代码复制出来,它的构建和运行没有任何问题。诊断和修复都有效,因此看起来问题不在于您的代码。我遇到了多个诊断相互冲突的问题。尝试启动 Visual Studio 的调试实例并卸载任何其他诊断程序,然后清理并重建上述代码并重试

以上是关于C# Roslyn 更改注释类型的主要内容,如果未能解决你的问题,请参考以下文章

Roslyn代码生成,如何为给定类型创建一个类型表达式。

如何在 Roslyn 代码生成器中生成数组类型?

如何使用 Roslyn 为类中具有特定返回类型的所有属性添加 JsonIgnore 属性?

mysql怎么更改字段名

SWIG 更改 C# 的特定类型的字段类型

使用 Roslyn 编译 C# 项目时,如何避免完全重新编译?