【问题标题】:Connect code to using statement with Roslyn使用 Roslyn 将代码连接到 using 语句
【发布时间】:2020-12-08 21:18:11
【问题描述】:

有没有办法使用 Roslyn 框架将一段代码连接到它的“使用”语句?

例如,给定这段代码:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Serilog;
using System.Collections.Generic;

namespace CodeAnalyzer.Service.CodeAnalysis.CSharp
{
public static class CSharpCodeAnalyser
{

/// <summary>
/// Retrieves all of the using statements from a code page
/// </summary>
/// <param name="codeDocument"></param>
/// <param name="logger"></param>
/// <returns></returns>
public static List<string> IdentifyUsings(string codeDocument, ILogger logger)
{
    var usingList = new List<string>();

    try
    {
        SyntaxTree tree = CSharpSyntaxTree.ParseText(codeDocument);
        CompilationUnitSyntax root = tree.GetCompilationUnitRoot();
        foreach (var item in root.Usings)
        {
            usingList.Add(item.Name.ToString());
        }
    }
    catch (System.Exception ex)
    {
        logger.Error(ex, ex.Message);
        throw;
    }

    return usingList;
}

} }

我能知道“CSharpSyntaxTree”属于哪个程序集吗?

【问题讨论】:

  • 如果你有这些信息,你会用它做什么?我之所以问是因为围绕扩展方法有一些有趣的案例,您必须考虑这些案例,并且根据您的目标,您可能需要做不同的事情。
  • 所以基本上我正在尝试创建一个工具来分析对 git repo 的提交并确定在代码更新中使用了哪些库,以便我可以将其连接到开发人员。这样我就可以跟踪开发人员的技能
  • 你到底想要什么?知道名称空间或类型的程序集吗?您之前的评论与问题不符。
  • Paulo,看看我发布的示例。我想知道命名空间和程序集。但如果我必须选择一个,那就是大会。我想如果我能找到命名空间,我就可以使用我已经拥有的代码来识别程序集。但是一段可以同时完成这两项工作的简单代码将是最佳选择。
  • 那么您真的需要将类型连接到 usings,还是您真正的问题是“您只想知道类型来自哪些命名空间?”例如,您的假设工具是否认为“Foo”和“Fully.Qualified.Foo”都是“Fully.Qualified”的使用?

标签: roslyn roslyn-code-analysis


【解决方案1】:

所以我想出了如何做到这一点。

首先,我需要构建一个包含整个解决方案的工作区。我通过 Buildalyzer 工具做到了这一点

        public static Tuple<AdhocWorkspace, IEnumerable<Project>> GetWorkspace(string solutionFilePath, ILogger logger)
    {
        Tuple<AdhocWorkspace, IEnumerable<Project>> results;
        var projectList = new List<Project>();
        AdhocWorkspace workspace = new AdhocWorkspace();


        try
        {
            AnalyzerManager manager = new AnalyzerManager(solutionFilePath);
            foreach (var project in manager.Projects)
            {
                projectList.Add(project.Value.AddToWorkspace(workspace));
            }
            results = new Tuple<AdhocWorkspace, IEnumerable<Project>>(workspace, projectList);
        }
        catch (Exception ex)
        {
            logger.Error(ex, ex.Message);
            throw;
        }
        return results;
    }

一旦我有了工作空间,我需要做的就是以下几点:

var workspace = GetWorkspace(solutionName, _logger);


                foreach (var project in workspace.Item1.CurrentSolution.Projects)
                {
                    foreach (var document in project.Documents)
                    {
                        _logger.Information("");
                        _logger.Information(project.Name + "\t\t\t" + document.Name);
                        var semanticModel = await document.GetSemanticModelAsync();
                        var root = await document.GetSyntaxRootAsync();

                        foreach (var item in root.DescendantNodes())
                        {
                            var typeInfo = semanticModel.GetTypeInfo(item);
                            if (typeInfo.Type != null)
                            {
                                _logger.Information(String.Format("Node: {0}", item.ToString()));
                                _logger.Information(String.Format("Type:{0}", typeInfo.Type.Name.ToString()));
                                _logger.Information(String.Format("ContainingAssembly:{0}", typeInfo.Type.ContainingAssembly));
                                _logger.Information(String.Format("ContainingNamespace:{0}", typeInfo.Type.ContainingNamespace));
                            }

                        }

                        
                    }
                }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    相关资源
    最近更新 更多