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

时间:2015-08-03 20:23:52

标签: c# .net roslyn

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

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

4 个答案:

答案 0 :(得分:3)

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

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

从VS内部,您可以找到全球服务提供商(例如 feature.getProperty('name')//should return 'ExampleCountry' ),然后获取ServiceProvider.GlobalProvider(VS自己的MEF图的根)并抓住Roslyn' s SComponentModel。请注意,这是一种有点脆弱的方法,并且在VS之外根本不起作用。

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

答案 1 :(得分: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);
}

答案 2 :(得分:2)

我想出了一种通过反射来实现这一目标的方法,我只在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();
}

答案 3 :(得分:1)

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

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

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

这里是代码,请参阅名为FindProjectFile的方法:https://nsdepcop.codeplex.com/SourceControl/changeset/view/75896#VS2015/source/NsDepCop.VisualStudioIntegration/ProjectAnalyzerRepository.cs