检查ObjectCreationExpressionSyntax的参数是否包含在try catch块中

时间:2016-11-24 12:30:28

标签: c# .net code-analysis roslyn

我正在尝试用roslyn编写代码分析规则。

基本上,我必须检查创建Microsoft.Practices.Prism.Commands.DelegateCommand()的每个参数是否都包含在try catch中。

主要思想是收集ObjectCreationExpressionSyntax类的所有DelegateCommand个对象,如果第一个StatementSyntaxTryStatementSyntax,则检查每个构造函数的参数。

您可以帮助我从StatementSyntax获取所有ArgumentSyntax吗?或者你可能有另一种方法吗?

public IEnumerable<IdentifierInfo> Collect(SyntaxNode rootNode, SemanticModel semanticModel)
{
    ObjectCreationExpressionSyntax[] objCreation = rootNode
                                                    .DescendantNodes()
                                                    .OfType<ObjectCreationExpressionSyntax>()
                                                    .Where(c=>(c.Type as IdentifierNameSyntax)?.Identifier.Value.ToString() == "DelegateCommand")
                                                    .ToArray();

    foreach (var obj in objCreation)
    {
        var args = obj.ArgumentList.Arguments;

        foreach (ArgumentSyntax arg in args)
        {
            var expession = arg.Expression;
            var symbol = semanticModel.GetSymbolInfo(expession).Symbol as IMethodSymbol;
        }
    }
}

Bellow你可以找到我实际编译的搜索内容:

public class Program
{
    public delegate void MyDelegate();
    public static void DelegateMethod() { try { } catch { } }
    public static void Main(string[] args)
    {
        DelegateCommand del1 = new DelegateCommand(() => {try{}catch{}});
        DelegateCommand del2 = new DelegateCommand(new Action(() => { }));
        DelegateCommand del3 = new DelegateCommand(DelegateMethod);
        var barInit = (Action)(DelegateMethod);
        DelegateCommand del4 = new DelegateCommand(barInit);
        ICommand test;
        test = new Microsoft.Practices.Prism.Commands.DelegateCommand(() => { });
    }
}

1 个答案:

答案 0 :(得分:2)

你从一个好的方式开始,但要完全处理它,它需要更多的工作。

让我们看一下我们的内容

LINQ result (屏幕截图来自LINQ debugging featureOzCode

我写的是

var argsExpr = objCreation.Select(o => o.ArgumentList.Arguments.First())

正如您在窗口右侧所看到的,我们在参数中有三种类型的语法节点,因此我们没有一般方法来处理它们。

您有两种方法可以处理它。

  1. 写入获取SyntaxNode的方法,并根据其类型检查第一个语句是否为try \ catch语句
  2. 编写SyntaxWalker并访问相关方法,然后检查第一个语句是否为try \ catch语句
  3. 例如,为了处理ParenthesizedLambdaExpressionSyntax的第一个案例,您需要编写类似这样的内容(或者自己或通过覆盖Visit的相应SyntaxWalker方法)

    public static bool IsTryStatement(ParenthesizedLambdaExpressionSyntax node)
    {
        return ((BlockSyntax) node.Body).Statements.First() is TryStatementSyntax;
    }
    

    这只是一个例子。在您的真实代码中,您需要处理所有情况。

    对于IdentifierNameSyntax,您需要先获取方法符号:

    semanticModel.GetSymbolInfo(identifier).Symbol
    

    然后你需要从DeclaringSyntaxReferences获取语法节点并使用span,或者你可以使用符号的location或任何其他方式(ConstructFrom)。