【问题标题】:How to get solution path in .NET code analyzer如何在 .NET 代码分析器中获取解决方案路径
【发布时间】:2017-05-25 11:34:52
【问题描述】:

如何访问在 Roslyn 代码分析器中编译的项目/解决方案的文件路径?我需要根据与代码相关的一些规范文件来验证代码。不起作用的事情:

SyntaxTreeAnalysisContext.Tree.FilePath
Assembly.GetExecutingAssembly().Location
AppDomain.CurrentDomain.BaseDirectory
Environment.CurrentDirectory
Path.GetFullPath(relativePath)

【问题讨论】:

  • Roslyn 分析器存在于工作区层之下;解决方案可能实际上并不存在。
  • 所以定义上是不可能的?
  • 如果你努力,你可以让它只在 VS 中工作(尝试从全局 ServiceProvider 获取 SComponentModel,然后获取 Roslyn VisualStudioWorkspace)。但是,这会很脆弱,并且在 VS 之外根本不起作用。
  • @slaks。您应该真正回答问题,而不是仅仅发布带有答案的评论。

标签: c# .net roslyn


【解决方案1】:

分析器存在于工作区级别之下(它们由编译器直接运行),因此可能不存在解决方案。

由于复杂的原因,它们不是由 MEF 创建的,因此即使它确实存在,也没有简单的方法可以得到它。

在 VS 中,您可以找到全局服务提供商(例如,ServiceProvider.GlobalProvider),然后获取 SComponentModel(VS 自己的 MEF 图的根)并从中获取 Roslyn 的 VisualStudioWorkspace。请注意,这是一种有点脆弱的方法,并且在 VS 之外根本不起作用。

即使在 VS 中,这也会以奇怪的方式破坏预览窗格、杂项文件和其他不属于全局解决方案的上下文中的分析。

【讨论】:

    【解决方案2】:

    没有反射就不可能从分析器或修复器中获得解决方案。

    使用additional files 存储设置。

    在项目中:

    <ItemGroup>
      <AdditionalFiles Include="MyConfig.config" />
    </ItemGroup>
    

    在分析器中:

    private const string ConfigFileName = "MyConfig.config";
    
    private static string LoadConfig(ImmutableArray<AdditionalText> additionalFiles, CancellationToken cancellationToken)
    {
        var file = additionalFiles.SingleOrDefault(f => string.Compare(Path.GetFileName(f.Path), ConfigFileName, StringComparison.OrdinalIgnoreCase) == 0);
        if (file == null)
        {
            return null;
        }
    
        var fileText = file.GetText(cancellationToken);
    
        using (var stream = new MemoryStream())
        {
            using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
            {
                fileText.Write(writer, cancellationToken);
            }
    
            stream.Position = 0;
    
            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }
    
    private static void HandleCompilationStart(CompilationStartAnalysisContext context)
    {
        var config = LoadConfig(context.Options.AdditionalFiles, context.CancellationToken);
    }
    

    【讨论】:

    • WorkspaceAnalyzerOptions 是内部的,你怎么能这样做
    • 感谢您以这种方式回答最初我找到了一种通过打猎的方法。一会儿我会给出答案
    【解决方案3】:

    我想出了一种通过反射来做到这一点的方法,我只在 windows 环境中测试过。

    public static class RoslynExtensions
    {
        public static Solution GetSolution(this SyntaxNodeAnalysisContext context)
        {
            var workspace = context.Options.GetPrivatePropertyValue<object>("Workspace");
            return workspace.GetPrivatePropertyValue<Solution>("CurrentSolution");
        }
    
        public static T GetPrivatePropertyValue<T>(this object obj, string propName)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
    
            var pi = obj.GetType().GetRuntimeProperty(propName);
    
            if (pi == null)
            {
                throw new ArgumentOutOfRangeException(nameof(propName), $"Property {propName} was not found in Type {obj.GetType().FullName}");
            }
    
            return (T)pi.GetValue(obj, null);
        }
    }
    

    从分析器调用,如下所示:

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSyntaxNodeAction(AnalyzeConstDeclaration, SyntaxKind.FieldDeclaration);
    }
    
    public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
    {
         var solution = context.GetSolution();
    }
    

    【讨论】:

      【解决方案4】:

      这是另一种不使用 VS 的方法;也很脆,但出于不同的原因。 :)

      通过从当前语法树的源文件路径开始向上搜索文件夹层次结构来查找文件级别的 csproj。

      当然在某些情况下它不会起作用(如果源文件在 csproj 文件夹的子树之外,例如链接文件;或者周围有其他陈旧的 csproj 文件等)唯一的安全网我可以想到的是检查找到的 csproj 是否真的与当前 SemanticModel.Compilation.AssemblyName 所指的程序集名称相同,因此我们最终不会得到其他随机项目的 csproj。

      代码如下,见方法叫 FindProjectFile:https://nsdepcop.codeplex.com/SourceControl/changeset/view/75896#VS2015/source/NsDepCop.VisualStudioIntegration/ProjectAnalyzerRepository.cs

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多