如何从roslyn代码分析器输出文件?

时间:2017-06-12 09:32:54

标签: c# visual-studio roslyn roslyn-code-analysis

我正在使用roslyn API编写DiagnosticAnalyzer和CodeFix。

在我收集了所有字符串和字符串插值后,我想将它们全部写入文件,但我不知道如何以最佳方式执行此操作。

当然,我总是可以简单地做File.WriteAllText(...),但我想向用户公开更多控制权。

我也不确定如何最好地触发生成此文件,所以我的问题是:

  1. 我不想对文件名进行硬编码,将此设置公开给代码分析器用户的最佳方法是什么?配置文件?如果是这样,我将如何访问?即:我如何知道目录?

  2. 如果文件中缺少一个字符串,我想建议一个代码修复,如“项目包含已更改或新字符串,重新生成字符串文件”。这是最好的方法吗?或者是否可以在视觉工作室中添加按钮或其他内容?

  3. 我从命令行调用devenv.com可执行文件来触发构建,是否有办法强制我的代码修复在构建时或之前/之后运行?或者我是否必须使用roslyn“手动”加载解决方案并执行我的codefix?

2 个答案:

答案 0 :(得分:1)

对于配置文件,您可以使用AdditionalFiles msbuild属性,该属性通过上下文传递给分析器。请参阅here

答案 1 :(得分:1)

我刚刚完成了一个项目。您需要做/知道一些事情。

  1. 您可能需要将可移植类库切换为类库。否则你将无法拨打File.WriteAllText()
  2. 您可以看到如何将便携式类库转换为常规here

    1. 尝试将所有更改应用于文档/项目/解决方案时,这可能无法正常工作。从文档/项目/解决方案调用时,更改将被预先计算并应用于预览窗口。如果取消,则会触发撤消操作以撤消所有更改,如果在此期间写入文件,并且未注册撤消操作,则不会撤消对文件的更改。
    2. 我已经用roslyn打开了一个错误,但您可以通过覆盖预览来处理实例,您可以看到如何执行此操作here

      1. 您可能需要知道的最后一件事是如何从分析仪访问解决方案,目前我已经编写了一个黑客攻击here

      2. 正如Tamas所说,您可以使用其他文件,您可以看到如何执行此操作here

      3. 您可以使用其他文件,但我知道我使用的是资源文件的版本,默认情况下它们没有标记为附加文件,它们是embeddedResources。
        因此,为了让我的用户不必手动将资源标记为additonalFiles,我编写了一个函数来使用xDoc从csproj文件中获取与资源文件关联的Designer.cs文件,如果您选择解析,则可以使用它作为示例csproj文件:

        protected List<string> GetEmbeddedResourceResxDocumentPaths(Project project)
        {
            XDocument xmldoc = XDocument.Load(project.FilePath);
            XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
        
            var resxFiles = new List<string>();
            foreach (var resource in xmldoc.Descendants(msbuild + "EmbeddedResource"))
            {
                string includePath = resource.Attribute("Include").Value;
        
                var includeExtension = Path.GetExtension(includePath);
                if (0 == string.Compare(includeExtension, RESX_FILE_EXTENSION, StringComparison.OrdinalIgnoreCase))
                {
                    var outputTag = resource.Elements(msbuild + LAST_GENERATED_TAG).FirstOrDefault();
        
                    if (null != outputTag)
                    {
                        resxFiles.Add(outputTag.Value);
                    }
                }
            }
            return resxFiles;
        }