使用Roslyn,如果我有一个IdentifierNameSyntax,我可以找到它引用的成员类型(字段,属性,方法......)

时间:2016-12-02 23:05:16

标签: metaprogramming aop roslyn

我正在尝试使用Roslyn SDK和StackExchange.Precompilation(谢谢!)在C#6中实现面向方面的编程。我现在的具体问题是,从IdentifierNameSyntax实例开始,我想找到"成员类型" (标识符所引用的(方法,属性,字段,变量等)。 (如何)可以这样做?

背景

我正在研究的第一个概念验证是一些旧的设计合同。我有一个NonNullAttribute,可以应用于参数,属性或方法返回值。除了属性之外,还有一个实现StackExchange.Precompilation.ICompileModule接口的类,在编译时将对标记的参数或返回值插入空检查。

这与PostSharp的NonNullAttribute相同,但转换是在Roslyn的一个语法树上完成的,而不是在已编译的程序集上。它也类似于Code Contracts,但是采用声明属性方法,并且再次在语法树上运行而不是IL。

例如,此源代码:

[return: NonNull]
public string Capitalize([NonNull] string text) {
    return text.ToUpper();
}

将在预编译期间转换为此内容:

[return: NonNull]
public string Capitalize([NonNull] string text) {
    if (Object.Equals(text, null)) 
        throw new ArgumentNullException(nameof(text));

    var result = text.ToUpper();
    if (Object.Equals(result, null))
        throw new PostconditionFailedException("Result cannot be null.");
    return result;
}

PostconditionFailedException是我为了补充ArgumentException的返回值而做出的自定义异常。如果框架中已有类似内容,请告知我们。)

对于具有此属性的属性,会有类似的转换,但前提条件和后置条件分别在setget访问器中实现。

我需要找到"成员类型的具体原因"这里的标识符用于实现后置条件的优化。请注意,在上面的后编译示例中,将返回的值存储在局部变量中,进行检查,然后返回本地。此存储对于转换评估方法或复杂表达式的return语句是必需的,但如果返回的表达式只是字段或局部变量引用,则创建本地临时存储是浪费的。

因此,在扫描return语句时,我首先检查语句的格式是ReturnKeyword - IdentifierSyntaxToken - SemicolonToken。如果是这样,那么我需要检查该标识符引用的内容,因此如果引用对象是字段或var,我会避免使用局部变量分配。

更新 有关更多上下文,请查看参考GitHub上的项目。

2 个答案:

答案 0 :(得分:2)

您需要使用SemanticModel.GetSymbolInfo来确定标识符绑定的符号。

答案 1 :(得分:0)

使用SemanticModel.GetTypeInfo.Type获取TypeInfo并使用它来探索Type