例 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 のレッスンを使用して基本クラスをチェックすることもできます。