例 7:カスタム関数でノードのトラバースを使用する
例を使用する目的で、同じクラスのメンバー変数への割り当てを検索し、指定の関数ノードのさまざまなステートメントを通じて繰り返します。
#include <stdio.h> #include <XPath_plugins.h> #include <ktcAPI.h> int logAssignments(ktc_tree_t node) { ktc_semanticInfo_t si = ktc_getSemanticInfo(node); fprintf(stderr, "Looking for assignments in function %s\n", ktc_sema_getQualifiedName(si)); // Check that the function definition incoming is a member function ktc_semanticInfo_t ci = ktc_sema_getScope(si); if( ci == 0 || !ktc_sema_isClass(ci) ) return 0; // Incoming 'node' is a FuncDef node, so let's get into its CompoundStmt // This is the equivalent of the KAST expression: // // FuncDef / FuncBody / Stmt::CompoundStmt / Stmts[*]::DeclOrStmt TRULE stmts[] = { {cid_FuncBody, tid_Any}, {cid_Stmt, tid_CompoundStmt}, {cid_Stmts, tid_Any}, {0, 0} }; node = traverse(node, stmts); // For a simple implementation, let's check each ExprStmt we find at // the top level while( !ktc_is_NoDeclOrStmt(node) ) { // Do we have an expression? if( ktc_is_ExprStmt(node) ) { // Make sure it's a binary expression of type '=' ktc_tree_t expr = ktc_proceed(node, cid_Expr); if( ktc_is_BinaryExpr(expr) && (ktc_getOperation(expr) == KTC_OPCODE_ASSIGN) ) { // Make sure the LHS is an identifier or a member reference ktc_tree_t left = ktc_proceed(expr, cid_Left); if( ktc_is_IdExpr(left) ) { // Make sure it's a member of the same class if( ktc_sema_getScope(ktc_getSemanticInfo(left)) == ci ) fprintf(stderr, "Basic assignment to %s\n", ktc_getIdentifier(left)); } else if( ktc_is_MemberExpr(left) ) { TRULE name[] = { { cid_Name, tid_Any }, { 0, 0 } }; fprintf(stderr, "Member assignment to %s\n", ktc_getIdentifier(traverse(left, name))); } } } // On to the next statement in the compound node = ktc_proceed(node, cid_Next); } return 1; } HOOKS_SET_START XPath_register_int_hook("logAssignments", logAssignments); HOOKS_SET_END
これはステートメントトラバースおよび LHS 試験 (エイリアスを処理しない、など) についてのネイティブの実装ですが、検索を妨げる基本アプローチを示しています。(同じ目標を達成するもっと良い方法は、次の例で示します。
この例を実行するには、チェッカーの定義を変更して次のパターンを使用します。
// FuncDef [ logAssignments() ]
次に、テストケースを次のように変更します。
class CBar { protected: bool m_z; }; class CFoo : public CBar { public: void init(int x, const char* y); private: int m_x; const char* m_y; }; void CFoo::init(int x, const char* y) { int i; i = 32; m_x = x; this->m_y = y; m_z = true; }
'make' 命令を使用してチェッカーを実行すると、ビルドログにこの出力が含まれます。
Looking for assignments in function CFoo::init Basic assignment to m_x Member assignment to m_y
メンバー変数 'm_z' への割り当てが反映されていないことに注意してください。これは基本クラスのメンバーであるため、同じクラスに存在することをチェックできません。(例を拡張して、例 4 のレッスンを使用して基本クラスをチェックすることもできます。