我正在尝试为Visual Studio做一个更改代码中某些语法的扩展。 实际上,我已经完成了第一步,即改变变量的名称,如果这个名称不是我们在公司使用的规则。例如:
int newVariable;
double test;
将更改为:
int iNewVariable;
double dblTest;
现在我必须更改此类评论:(SingleLineComment)
//this is a single line Comment
进入MultiLineComment
/*Here it's a MultiLine one*/
我使用Roslyn语法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"));
}
}
}
}
这是CodeFix:
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;
}
}
}
用户必须点击我的程序提供的广告,评论才会更改。
但我的程序永远不会进入我必须调用方法的地方。
我正在与罗斯林迈出第一步,所以我不知道很多事情,但我正在学习它......
修改
添加了所有代码
答案 0 :(得分:8)
我使用带有Diagnostic的CodeFix组合了一个示例,该示例用多行注释替换单行注释。这是一些代码。很多都是基于Dustin Campbell在Build中的Roslyn演示,可以在http://channel9.msdn.com/Events/Build/2014/2-577看到
从ISyntaxTreeAnalyzer分析ResoformTree实现以查找单行注释:
[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;
}