Example 7: Using node traversal in a custom functionJust for the purposes of example, we'll iterate through the various statements in the provided function node, looking for assignments to member variables of the same class: #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 Although this is a native implementation in terms of statement traversal and LHS examination (for example, it doesn't handle aliases), it shows a basic approach to block searching. (A better way of achieving the same goal is shown in the next example.) To exercise this example, modify your checker definition to use the following pattern: // FuncDef [ logAssignments() ] Then modify the test case to something like this: 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; } Now when you execute the checker using the 'make' instruction, the build log should contain this output: Looking for assignments in function CFoo::init Basic assignment to m_x Member assignment to m_y Note that the assignment to member variable 'm_z' is not reflected. This is a member of a base class, so it fails the check for being in the same class. (We could extend the example to check base classes using lessons learned in Example 4.) |