如何在.net代码分析器中获取解决方案路径

本文关键字:获取 解决方案 路径 分析器 代码 net | 更新日期: 2023-09-27 18:06:14

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

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

如何在.net代码分析器中获取解决方案路径

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

由于复杂的原因,它们不是由MEF创建的,所以即使它存在,也没有简单的方法来获取它。

从VS内部,你可以找到全球服务提供商(例如,ServiceProvider.GlobalProvider),然后得到SComponentModel (VS自己的MEF图的根),并从中获取Roslyn的VisualStudioWorkspace。注意,这是一种脆弱的方法,在vs

之外根本不起作用。

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

我通过反射找到了一种方法,我只在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();
}

如果没有反射,就不可能从分析器或固定器中获得解决方案。

使用其他文件来存储设置

在项目:

<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);
}

这是另一种没有VS的方法;也很脆,但原因不同。:)

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

当然,它不会在某些情况下工作(如果源文件是csproj的文件夹的子树之外,例如;相关文件;或者有其他陈旧的csproj文件躺在周围等)我能想到的唯一安全网是检查发现的csproj是否真的与当前semanticmodel . compile . assemblyname引用的程序集名称相同,因此我们不会以其他随机项目的csproj结束。

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