如何编写C#/Roslyn分析器以匹配ReactiveUI属性?
如果我有以下惯用的属性声明如何编写C#/Roslyn分析器以匹配ReactiveUI属性?,c#,roslyn-code-analysis,C#,Roslyn Code Analysis,如果我有以下惯用的属性声明 private int _Foo; public int Foo { get { return _Foo; } set { this.RaiseAndSetIfChanged(ref _Foo, value); } } 其中Foo可以是whatshover的任何名称。作为roslyn分析仪的一部分,诊断匹配器是什么 我已经准备好编写我想要的代码修复,但目前我允许它应用于任何属性。我想收紧它,这样它只适用于与上述形状完全相同的属性 我目前的尝试是使用
private int _Foo;
public int Foo {
get { return _Foo; }
set { this.RaiseAndSetIfChanged(ref _Foo, value); }
}
其中Foo可以是whatshover的任何名称。作为roslyn分析仪的一部分,诊断匹配器是什么
我已经准备好编写我想要的代码修复,但目前我允许它应用于任何属性。我想收紧它,这样它只适用于与上述形状完全相同的属性
我目前的尝试是使用正则表达式剥离琐事,然后执行ToString,然后精确匹配字符串输出。我不确定是否有更好的方法
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace ReactiveUI.Fody.CodeFix
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ReactiveUIFodyCodeFixAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "ReactiveUIFodyCodeFix";
// You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization
private static readonly string Title = "ReactiveUI.Fody CodeFix";
private static readonly string MessageFormat = "The property {0} can be simplified using ReactiveUI.Fody";
private static readonly string Description =
"This code fix changes boiler plate INPC property declaration to simple ones using a fody attribute";
private const string Category = "Properties";
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(ChangePropertyModifierRule, SymbolKind.Property);
}
private static void ChangePropertyModifierRule(SymbolAnalysisContext context)
{
var propertySymbol = context.Symbol as IPropertySymbol;
// Check if the ReactiveAttribute is already applied and if so
// skip it.
var attributes = propertySymbol.GetAttributes();
if (attributes.Any(attr => attr.AttributeClass.Name == "Reactive"))
return;
if (propertySymbol != null)
{
var property = propertySymbol.DeclaringSyntaxReferences[0].GetSyntax() as PropertyDeclarationSyntax;
Debug.Assert(property != null, "property != null");
var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration));
if (setter?.Body == null)
return;
if (getter?.Body == null)
return;
if (setter.Body.Statements.Count != 1)
return;
var statement = setter.Body;
if (!statement.ToString().Contains("RaiseAndSetIfChanged"))
return;
var idiom = $"{{this.RaiseAndSetIfChanged(ref_{propertySymbol.Name},value);}}";
var noWhiteSpace = System.Text.RegularExpressions.Regex.Replace(statement.ToString(), @"\s+", "");
if (idiom != noWhiteSpace)
return;
// Add "contextual" menu to change property modifiers.
var diagnostic = Diagnostic.Create(Rule, propertySymbol.Locations[0], propertySymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
使用System.Linq;
使用系统线程;
使用Microsoft.CodeAnalysis;
使用Microsoft.CodeAnalysis.CSharp;
使用Microsoft.CodeAnalysis.CSharp.Syntax;
使用Microsoft.CodeAnalysis.Diagnostics;
命名空间ReactiveUI.Fody.CodeFix
{
[诊断分析仪(LanguageNames.CSharp)]
公共类ReactiveUIFodyCodeFixAnalyzer:DiagnosticanAnalyzer
{
public const string DiagnosticId=“ReactiveUIFodyCodeFix”;
//您可以在Resources.resx文件中更改这些字符串。如果您不希望您的分析器能够本地化,可以使用常规字符串作为标题和消息格式。
//看https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md 有关本地化的更多信息
私有静态只读字符串Title=“ReactiveUI.Fody CodeFix”;
私有静态只读字符串MessageFormat=“可以使用ReactiveUI.Fody简化属性{0}”;
私有静态只读字符串描述=
“此代码修复将锅炉板INPC属性声明更改为使用fody属性的简单声明”;
私有常量字符串Category=“Properties”;
私有静态只读DiagnosticDescriptor规则=新的DiagnosticDescriptor(DiagnosticId、标题、消息格式、类别、DiagnosticSeverity.Warning、isEnabledByDefault:true、描述:description);
公共覆盖ImmutableArray SupportedDiagnostics=>ImmutableArray.Create(规则);
公共覆盖无效初始化(AnalysisContext上下文)
{
RegisterSymbolAction(ChangePropertyModifierRule,SymbolKind.Property);
}
私有静态void ChangePropertyModifierRule(SymbolAnalysisContext上下文)
{
var propertySymbol=上下文。符号为IPropertySymbol;
//检查是否已应用ReactiveAttribute,如果已应用
//跳过它。
var attributes=propertySymbol.GetAttributes();
if(attributes.Any(attr=>attr.AttributeClass.Name==“被动”))
返回;
if(propertySymbol!=null)
{
var property=propertySymbol.DeclaringSyntaxReferences[0].GetSyntax()作为PropertySclarationSyntax;
Assert(property!=null,“property!=null”);
var getter=property.AccessorList?.Accessors.FirstOrDefault(x=>x.IsKind(SyntaxKind.GetAccessorDeclaration));
var setter=property.AccessorList?.Accessors.FirstOrDefault(x=>x.IsKind(SyntaxKind.SetAccessorDeclaration));
if(setter?.Body==null)
返回;
if(getter?.Body==null)
返回;
if(setter.Body.Statements.Count!=1)
返回;
var语句=setter.Body;
如果(!statement.ToString()包含(“RaiseAndSetIfChanged”))
返回;
var-idiom=$“{{this.RaiseAndSetIfChanged(ref{propertySymbol.Name},value);}}”;
var noWhiteSpace=System.Text.RegularExpressions.Regex.Replace(statement.ToString(),@“\s+”,”);
if(成语!=noWhiteSpace)
返回;
//添加“上下文”菜单以更改属性修改器。
var diagnostic=diagnostic.Create(规则,propertySymbol.Locations[0],propertySymbol.Name);
上下文。报告诊断(诊断);
}
}
}
}
是否也应识别此项:RaiseAndSetIfChanged(参考此值)代码>?如果属性X
的基础字段被称为X
(甚至是\u y
),该怎么办?是的,但idomatic方式是from。我在ReactiveUI上有一个打开拉取请求。Fody在。如果您愿意帮助使用更灵活的分析仪,我们将不胜感激。问题是:您现在拥有的功能正在发挥作用。你在问我们一个更好的方法,但你必须告诉我们这意味着什么。如何更好?产生完全相同的匹配,但以更有效的方式?或者在匹配的方面做得更好(因此也不同)?给我们举个例子,问一个具体的问题。我问这个问题时没有答案。但是现在,我想还是不要在整个语句中使用字符串匹配更好。因此,准确地说,“更好”的方法是通过某种方法在语法树上执行模式匹配。但我可能又错了,这可能是最好的方式做这样的事情。这是我的第一个分析器,在写这个问题的时候,我还不知道如何得到任何解决方案。请注意,我使用正则表达式折叠所有空白(删除所有琐事),然后将其与预期值进行比较。我希望看到等效的代码,它将语法树中的所有琐事剥离出来,然后与预期的语法树进行比较,而不将整个语法树折叠成字符串。是否也可以识别这一点:RaiseAndSetIfChanged(请参阅此值)。\u Foo代码>?如果属性X
的基础字段被称为X
(甚至是\u y
),该怎么办?是的,但idomatic方式是from。我在ReactiveUI上有一个打开拉取请求。Fody在。如果您愿意帮助使用更灵活的分析仪,我们将不胜感激。问题是:您现在拥有的功能正在发挥作用。你在问我们一个更好的方法,但你必须告诉我们这意味着什么。如何更好?产生完全相同的匹配,但以更有效的方式?或者在匹配的方面做得更好(因此也不同)?给我们举个例子,问一个具体的问题。我问这个问题时没有答案。但现在我知道了,我想还是会更好