Start here

Home
About Klocwork
What's new
Fixed issues
Release notes
Installation

Reference

C/C++ checkers
Java checkers
C# checkers
MISRA C 2004 checkers
MISRA C++ 2008 checkers
MISRA C 2012 checkers
MISRA C 2012 checkers with Amendment 1
Commands
Metrics
Troubleshooting
Reference

Product components

C/C++ Integration build analysis
Java Integration build analysis
Desktop analysis
Refactoring
Klocwork Static Code Analysis
Klocwork Code Review
Structure101
Tuning
Custom checkers

Coding environments

Visual Studio
Eclipse for C/C++
Eclipse for Java
IntelliJ IDEA
Other

Administration

Project configuration
Build configuration
Administration
Analysis performance
Server performance
Security/permissions
Licensing
Klocwork Static Code Analysis Web API
Klocwork Code Review Web API

Community

View help online
Visit RogueWave.com
Klocwork Support
Rogue Wave Videos

Legal

Legal information

Example 5: Traversing the AST tree

Having looked at semantic information, let's look now at how our custom function might traverse the AST node tree. While a KAST expression makes this traversal very simple, there are times when you need to perform traversal within a custom function, which you can do with the ktc_proceed() API.

Simple KAST expression

Let's start with a simple KAST expression, such as:

// FuncDef / FuncBody / Stmt::CompoundStmt / Stmts[*]::ExprStmt

This expression navigates from a function definition into its body through the compound statement that bounds its content, and picks the first top-level expression statement in that compound.

 void foo(int someParams)
 {
   int someVariables;
  
     for( ... ) { }
     someVariables = 32;                // This ExprStmt will be our result
 }


In this exercise, our custom function, invoked on the usual FuncDef node, needs to traverse the function's various statements and do something with each expression statement. You can use the ktc_proceed() function for this purpose.

ktc_proceed() function

The ktc_proceed() function takes a starting node and a designator for an edge through which the checker should progress. If you examine a FuncDef node in Checker Studio, you'll see that it generally has child edges:

FuncDef
        DeclSpecs[] :: DeclSpec
        Declarator :: MaybeDeclarator
        KRParams[] :: DeclOrStmt
        FuncBody :: AnyFuncBody

Checker Studio's representation of the AST shows that from a FuncDef node, you can proceed through four different child edges (DeclSpecs, Declarator, KRParams and FuncBody), each of which has a particular specialization (DeclSpec, MaybeDeclarator, DeclOrStmt, and AnyFuncBody). To see the specialization for an edge, simply expand the node of interest and you'll see something like:

FuncDef
        DeclSpecs[] :: DeclSpec
                BuiltinType
        Declarator :: MaybeDeclarator
                Declarator
        KRParams[] :: DeclOrStmt
        FuncBody :: AnyFuncBody
                FuncBody

For example, if we want our checker to find all void functions in KAST, we could specialize our FuncDef like this:

 // FuncDef / DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ]


To achieve this objective using the ktc API, you can use a function sequence something like:

 // Assume we start with 'node' referencing the FuncDef node, as usual
 int isVoid(ktc_tree_t node)
 {
   return
     ( (node = ktc_proceed(node, cid_DeclSpecs)) != 0 ) &&
     ( ktc_isTreeType(node, tid_BuiltinType) ) &&
     ( ktc_getBuiltinType(node) == KTC_BUILTINTYPE_VOID ) ? 1 : 0;
 }
   
 HOOKS_SET_START
   ...
   XPath_register_int_hook("isVoid", isVoid);
 HOOKS_SET_END

Now that same KAST statement can be simplified to:

 // FuncDef [ isVoid() ]

Note that in a real-world situation, you would be more likely to check a function's type through its semantic information with ktc_sema_getFunctionType(), but the ktc_proceed() usage shown suits our example.