2016-06-14 9 views
2

を呼び出すオブジェクトを分析:ロザリン:例えば方法

SqlCommand command = new SqlCommand(); 
SqlDataReader datareader = command.ExecuteReader(); 

ここで呼び出しノードがcommand.ExecuteReader()あります。 roslynを使用して、変数識別子トークン/ノードcommandを起動ノードから取得するにはどうすればよいですか?この呼び出しノードは、その前に他の多くのメソッド呼び出しを持つことができると仮定する。 classA.methodA().methodB().classB.methodC(command.ExecuteReader())であるため、node.DescendantNodesで識別子を取得すると便利ではない可能性があります。 私が考えた解決策は、最初にExecuteReaderのスパンスタートを取得し、次にcommandのシンボルをSymbolFinder.FindSymbolAtPositionと呼び、ExecuteReader.SpanStart - 2の位置でコールすることでした。しかし、このソリューションがあらゆる状況に対応できるかどうかは不明です。私が取り組んでいるアプリケーションは静的コードアナライザです。

+3

は、それらは、単に呼び出し/単純なメンバーがアクセス連鎖されます。一番内側の呼び出し(または 'SimpleMemberAccessExpression')を取得した場合、必要なものが得られます。すべての祖先ではなく、直系の親を見てください。 –

+0

は、ハードコーディングするのではなく、より良い方法ですか?たとえば、メソッド呼び出しのシンボルを取得し、次にシンボルから、メソッドを呼び出すオブジェクトのインスタンスを特定します。たとえば、次のようになります。 'ClassA varA = new ClassA(); varA.methodA() 'は' methodA() 'のシンボルを取得し、' varA'が呼び出すことがわかります。 –

+0

「ハードコーディング」とはどういう意味ですか?その呼び出しが必要な場合は、呼び出しを取得するコードを記述する必要があります。 –

答えて

4

呼び出しノードがある場合、その式がメンバーアクセスかどうかを確認できます。呼び出しがステートメント "DoThis()"の場合、メンバーアクセスは存在しませんが、呼び出しが "x.DoThis()"の場合、はです。参照 "x"。

がメンバーアクセスであることを確認すると、ターゲット参照の表現を得ることができます。これは、そのメンバーがアクセスされている参照です。この式は、単純な名前識別子(例えば "command")であっても、別のメンバアクセス(例えば "x.command")であっても、別の呼び出し(例えば "GetCommand()")であってもよいこれらの組み合わせコードで例示する

- エンドで

private static void AnalyseInvocation(SyntaxNodeAnalysisContext context) 
{ 
    var invocation = (InvocationExpressionSyntax)context.Node; 
    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; 
    if ((memberAccess == null) || (memberAccess.Name.Identifier.ValueText != "ExecuteReader")) 
     return; 

    if (memberAccess.Expression is IdentifierNameSyntax) 
    { 
     // The target is a simple identifier, the code being analysed is of the form 
     // "command.ExecuteReader()" and memberAccess.Expression is the "command" 
     // node 
    } 
    else if (memberAccess.Expression is InvocationExpressionSyntax) 
    { 
     // The target is another invocation, the code being analysed is of the form 
     // "GetCommand().ExecuteReader()" and memberAccess.Expression is the 
     // "GetCommand()" node 
    } 
    else if (memberAccess.Expression is MemberAccessExpressionSyntax) 
    { 
     // The target is a member access, the code being analysed is of the form 
     // "x.Command.ExecuteReader()" and memberAccess.Expression is the "x.Command" 
     // node 
    } 
} 
+0

hmm ..しかし、呼出し式の長いチェーンがまだ機能するのでしょうか?例えば、node.ChildNodes()。OfType ()。Single()。Name'は、Visual Studioのシンタックスビジュアライザから、Single()のinvocation.expressは 'node.ChildNodes()。OfType < MemberAccessExpressionSyntax>()。Single'構文ビジュアライザーから 'MemberAccessExpressionSyntax'ですので、' x.Command.ExecuteReader() "'の条件を満たしていません。ありがとう!非常に遅い返信をおかけして申し訳ありません。笑。 –

+0

私はあなたのコードを誤解していると思うので、実際には 'invocation.Expression.Expression'を実際にチェックしていますか?その場合、私はあなたが正しいと思っています –

+0

@KimKangInはい、私は本質的にinvocation.Expression.Expressionをチェックしています - これはチェーンがどれほどシンプルか複雑であっても、 "ExecuteReader"コールの前に完全チェーンを返します。 "ExecuteReader"以外の呼び出しを無視するようにコード例を少し変更しました。このコードをIDEで実行し、最初の "if(memberAccess.Expression is .."という行にブレークポイントを設定するとmemberAccess参照を調べることで、呼び出し中の "ExecuteReader"の前に常に*すべて*であることがわかります。 –