- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
随着新的 RC 版本的发布,我很高兴地看到现在有一个属性包允许 raised diagnostics 有额外的数据,在我看来,一个主要的用例是能够计算数据分析器转移到代码修复器中以监听该特定诊断。
我现在意识到这个属性包只允许存储字符串值。虽然这被证明是有用的,但我仍然发现自己必须在我的分析器和我的代码修复器中运行完全相同的逻辑,因为我没有能力只保留这些信息并传递它。我当然是在谈论更复杂的类型,例如语法节点和符号。
例如,我创建了一个分析器,它在每个文件中强制存在一组特定的 using
指令。分析器计算缺少哪些指令并提出诊断通知用户并以文本方式指示缺少的指令。如果我已经有了必须实现的 SyntaxNode
(我的分析器中已经有了),代码修复提供程序将非常简单,但我现在必须重新运行大部分相同的逻辑在我的代码修复器中(这就是为什么我最终将大量代码放在公共(public)静态辅助方法中的分析器中)
自从引入属性包以来,这个示例失去了一些相关性,但我仍然认为它是一个有效的用例。我特别担心分析器和代码修复器之间的唯一链接位于报告的诊断位置。在我的例子中,我可以有多个 DiagnosticDescriptor
实例,它们都可以代表不同的潜在问题,这些问题源于特定的“规则”,由 Diagnostic
及其 Id 定义
(我不知道这在 Roslyn 代码分析领域是否是一种好的做法,但似乎是一种可以接受的操作方式)。
底线是:对于相同的诊断 ID,我可能会根据情况在不同的位置(即在完全不同的语法元素上)引发诊断。因此,我失去了让所提供的位置位于确定和/或相关语法元素上的“确定性”,并且修复诊断的后续逻辑不存在。
那么,有什么方法可以将数据从分析器传递给相关的代码修复提供者吗?我还考虑过向下转换派生自 Diagnostic
的自定义类型的实例,但对我来说这似乎是一种代码味道,此外,Diagnostic
充满了抽象成员为了添加一个属性,我需要重新实现,并且 SimpleCodeFix
是密封的 (argggghhhh)
最佳答案
自从 Kevin 提到没有真正的方法来完成我在 native 尝试做的事情,因为诊断预计是可序列化的,这让我想到我可以通过序列化来模拟我想要的东西。我是发布我想出的解决方案来解决这个问题。请随意批评和/或强调一些潜在的问题。
SyntaxElementContainer
public class SyntaxElementContainer<TKey> : Dictionary<string, string>
{
private const string Separator = "...";
private static readonly string DeserializationPattern = GetFormattedRange(@"(\d+)", @"(\d+)");
private static string GetFormattedRange(string start, string end)
{
return $"{start}{Separator}{end}";
}
public SyntaxElementContainer()
{
}
public SyntaxElementContainer(ImmutableDictionary<string, string> propertyBag)
: base(propertyBag)
{
}
public void Add(TKey nodeKey, SyntaxNode node)
{
Add(nodeKey.ToString(), SerializeSpan(node?.Span));
}
public void Add(TKey tokenKey, SyntaxToken token)
{
Add(tokenKey.ToString(), SerializeSpan(token.Span));
}
public void Add(TKey triviaKey, SyntaxTrivia trivia)
{
Add(triviaKey.ToString(), SerializeSpan(trivia.Span));
}
public TextSpan GetTextSpanFromKey(string syntaxElementKey)
{
var spanAsText = this[syntaxElementKey];
return DeSerializeSpan(spanAsText);
}
public int GetTextSpanStartFromKey(string syntaxElementKey)
{
var span = GetTextSpanFromKey(syntaxElementKey);
return span.Start;
}
private string SerializeSpan(TextSpan? span)
{
var actualSpan = span == null || span.Value.IsEmpty ? default(TextSpan) : span.Value;
return GetFormattedRange(actualSpan.Start.ToString(), actualSpan.End.ToString());
}
private TextSpan DeSerializeSpan(string spanAsText)
{
var match = Regex.Match(spanAsText, DeserializationPattern);
if (match.Success)
{
var spanStartAsText = match.Groups[1].Captures[0].Value;
var spanEndAsText = match.Groups[2].Captures[0].Value;
return TextSpan.FromBounds(int.Parse(spanStartAsText), int.Parse(spanEndAsText));
}
return new TextSpan();
}
}
PropertyBagSyntaxInterpreter
public class PropertyBagSyntaxInterpreter<TKey>
{
private readonly SyntaxNode _root;
public SyntaxElementContainer<TKey> Container { get; }
protected PropertyBagSyntaxInterpreter(ImmutableDictionary<string, string> propertyBag, SyntaxNode root)
{
_root = root;
Container = new SyntaxElementContainer<TKey>(propertyBag);
}
public PropertyBagSyntaxInterpreter(Diagnostic diagnostic, SyntaxNode root)
: this(diagnostic.Properties, root)
{
}
public SyntaxNode GetNode(TKey nodeKey)
{
return _root.FindNode(Container.GetTextSpanFromKey(nodeKey.ToString()));
}
public TSyntaxType GetNodeAs<TSyntaxType>(TKey nodeKey) where TSyntaxType : SyntaxNode
{
return _root.FindNode(Container.GetTextSpanFromKey(nodeKey.ToString())) as TSyntaxType;
}
public SyntaxToken GetToken(TKey tokenKey)
{
return _root.FindToken(Container.GetTextSpanStartFromKey(tokenKey.ToString()));
}
public SyntaxTrivia GetTrivia(TKey triviaKey)
{
return _root.FindTrivia(Container.GetTextSpanStartFromKey(triviaKey.ToString()));
}
}
Use case (simplified for shortness' sake)
// In the analyzer
MethodDeclarationSyntax someMethodSyntax = ...
var container = new SyntaxElementContainer<string>
{
{"TargetMethodKey", someMethodSyntax}
};
// In the code fixer
var bagInterpreter = new PropertyBagSyntaxInterpreter<string>(diagnostic, root);
var myMethod = bagInterpreter.GetNodeAs<MethodDeclarationSyntax>("TargetMethodKey");
关于c# - 有没有办法在 Roslyn 的分析器和代码修复提供者之间传递数据(除了通过属性包)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30084293/
最初的问题是我有一个巨大的解决方案,其中项目有不同的选项(例如,x64 或 x86 配置、是否允许不安全代码等等)。我正在尝试使用 Roslyn (2.9.0) 通过 DEBUG x64 配置来编译\
当前的 .Net 编译器是完全独立的。 Roslyn 应该将它们组合成一个编译器。有谁知道这是否会引入在单个项目中使用多种语言的能力?或者甚至可能在单个文件/类中? 目前您能做的最好的事情就是在一个解
我已经开始使用 Roslyn 的语法和语义 API。还没有真正深入挖掘,但是语义 API 是否提供了任何代码优化,例如: 消除死代码,吊装或某种指针分析?或者其他分析? 我知道 roslyn 提供了
Roslyn 似乎提供了新的 API 来公开许多编译器内部数据结构以进行代码分析等。为此目的重写了 C# 和 VB 编译器。那么除了新的 API 之外,我还可以访问编译器源代码吗? 最佳答案 Rosl
我的解决方案在 roslyn 中构建正常,因此应该解析所有类型 我能够像这样获取在元数据程序集中定义的类型: string typeName = "MyCompany.MyLibrary.MyType
Roslyn 项目中的 CaaS(编译器即服务)是什么? 与当前 C# 4.0 编译器相比,使用 Roslyn 功能如何提高 C# 应用程序的性能? Roslyn-CTP 有哪些已知的限制/问题? 最
我们最近将构建系统从 VS 2013 升级到 2015 Update 2,构建时间显着增加。我们的构建环境是独立的,因此我们从包(使用 devpath)而不是从安装位置运行 MSBuild。查看日志,
我正在为 Roslyn 制作一个分析器。我正在做的是一种诊断,可以找到太长的方法。我想对任何被认为“太长”的内容进行可配置,最好是整个解决方案或项目的一种配置。解决这个问题的最佳方法是什么? 我想到的
如果我想在我的应用程序中支持脚本,是否 scriptcs提供比仅使用普通 Vanilla 的任何特殊优势 Roslyn脚本引擎? 最佳答案 不幸的是,目前还没有太多关于托管 scriptcs 的文档,
我创建了这个测试控制台应用程序,以使用 Roslyn 脚本引擎(在 Microsoft.CodeAnalysis.CSharp.Scripting nuget 包中)运行一些 C# 代码。
我对 stackoverflow 做了一些研究,但找不到我需要的结果。 我的问题是“如何使用 Roslyn 确定源文件的行代码位置”。 例如:我有一个源文件(名为:sample.cs)和它看起来像的内
来自 Visual Studio 2015 CTP5 包,如何获取当前的 Roslyn 工作区? 我在看 How to get reference to 'Roslyn' Workspace obje
我想在另一个非脚本 Roslyn 编译中将脚本作为动态程序集重用,但我终究无法弄清楚如何实现它。 例如,假设我以正常方式创建脚本,然后使用类似以下内容将脚本作为程序集发送到字节流: var compi
我使用 VS 2015 模板创建了一个 Roslyn 分析器。假设默认情况下启用了诊断,我的一切正常,包括单元测试。 如果我将DiagnosticDescriptor 上的isEnabledByDef
如何从 ITypeSymbol 获取基础类型对于 IEnumerable ?我明白了ITypeSymbol.OriginalDefinition包含指向 IEnumerable<> 的链接,但是我在哪
我有一个 VS 包项目,我需要从加载的 IVsSolution 访问 Roslyn 或 Microsoft.CodeAnalysis 的工作区或解决方案对象. 我需要知道如何实现这一目标? 我找到了t
我在做什么用一句话 查看分行 Update-1来自 Roslyn github repository ,构建 csc.exe,并使用我自己构建的 csc.exe 版本编译随机解决方案。 预期结果 我希
在我投入大量时间学习 roslyn 编译器服务之前,我想问一下 roslyn 是否可以实现以下场景。是否可以编译程序集而无需将任何内容写入磁盘并执行它?我基于元模型生成完整的解决方案,我想采用它并编译
我有一个带有两个输出 dll 的解决方案(实际上更多,但让我们保持简单)。项目“Special”引用项目“Common”。 我尝试编写一个代码生成器来解析“Special”中的一些文件,并将生成的 s
我创建了几个诊断分析器和代码修复。它们都按照预期在实验 hive 中工作。 我将它们构建为 Nuget 包,并添加到 VS2015 正常实例中的项目中。奇怪的是,分析器/代码修复组合之一可以正常工作,
我是一名优秀的程序员,十分优秀!