Roslyn 在 ObjectCreationExpressionSyntax 中获取 IdentifierName

Roslyn get IdentifierName in ObjectCreationExpressionSyntax

目前我正在使用 roslyn 对 c# 进行简单的代码分析。我需要在一个解决方案中解析所有项目的所有文档,并在该文档中获取已声明的已用 classes。

例如来自:

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();
    }
}

我想要 Program 使用 Foo

我已经解析了所有文档并在其中获取了声明的 class。

// all projects in solution
foreach (var project in _solution.Projects)
{
    // all documents inside project
    foreach (var document in project.Documents)
    {
        var syntaxRoot = await document.GetSyntaxRootAsync();
        var model = await document.GetSemanticModelAsync();
        var classes = syntaxRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
        // all classes inside document
        foreach (var classDeclarationSyntax in classes)
        {
            var symbol = model.GetDeclaredSymbol(classDeclarationSyntax);
            var objectCreationExpressionSyntaxs = classDeclarationSyntax.DescendantNodes().OfType<ObjectCreationExpressionSyntax>();
            // all object creations inside document
            foreach (var objectCreationExpressionSyntax in objectCreationExpressionSyntaxs)
            {
                // TODO: Get the identifier value
            }
        }
    }
}

问题是获取 IdentifierName Foo。使用 debugger,我看到 objectCreationExpressionSyntax.Type 得到了 Identifier.Text 得到了我需要的值,但是 objectCreationExpressionSyntax.Type.Identifier 似乎是私有的。

我可以使用 SymbolFinder 在解决方案中查找 Class 的所有引用。因为我已经需要解析所有文档,所以没有它应该可以工作。

也许我走错了路?如何获取标识符值?

您需要处理不同类型的 TypeSyntaxes。看这里:http://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Syntax/TypeSyntax.cs,29171ac4ad60a546,references

你在调试器中看到的是一个 SimpleNameSyntax,它确实有一个 public Identifier 属性.

更新

var ns = objectCreationExpressionSyntax.Type as NameSyntax;
if (ns != null)
{
  return ns.Identifier.ToString();
}

var pts = objectCreationExpressionSyntax.Type as PredefinedTypeSyntax;
if (pts != null)
{
  return pts.Keyword.ToString();
}

... 

所有其他子类型都需要提交。请注意 ArrayType.ElementType 也是一个 TypeSyntax,因此您很可能需要使此方法递归。

您可以从语法的类型中获取标识符 属性:

foreach (var objectCreationExpressionSyntax in objectCreationExpressionSyntaxs)
{
    IdentifierNameSyntax ins = (IdentifierNameSyntax)objectCreationExpressionSyntax.Type;
    var id = ins.Identifier;
    Console.WriteLine(id.ValueText);
}

字符串可能会产生误导。

假设您有表达式 new SomeClass(),并从中得到字符串 "SomeClass"。你怎么知道那是指 Namespace1.SomeClass 还是 Namespace2.SomeClass ?如果使用了 using SomeClass = Namespace3.SomeOtherType; 声明怎么办?

幸运的是,您不必自己进行此分析。编译器可以将 ObjectCreationExpressionSyntax 绑定到一个符号。你有你的语义模型,使用它。

foreach (var oce in objectCreationExpressionSyntaxs)
{
    ITypeSymbol typeSymbol = model.GetTypeInfo(oce).Type;
    // ...
}

您可以将此符号与从 model.GetDeclaredSymbol(classDeclarationSyntax) 获得的符号进行比较,只要确保您使用的是 Equals 方法,而不是 == 运算符。