Example 1: 'Hello world'
This example creates a checker that simply generates an error for each node on which it is called, doing nothing more than logging the fact that it was called. Following the usual pattern, we'll define a custom function called 'helloWorld()' and invoke it from a common AST node. This example shows:
Creating the KAST expressionAfter we create the checker stub files with kwcreatechecker, the first step is to edit checkers.xml to define a simple KAST expression that will invoke our custom function. This snippet shows the <pattern> attribute of the file: <pattern> // FuncDef [ helloWorld() ] </pattern> This pattern simply drives every function definition node into our custom function. (As well as the new pattern, it's useful to replace the title and message attributes of the error element to reflect the purpose of the checker.) For other examples of KAST expressions, see C/C++ KAST examples.
Editing the testcase fileFor this example, we'll use the basic test case that kwcreatechecker provides in the template testcase.cc file without modification.
Defining the custom functionThe next step is to define the custom function, 'helloWorld()'. If you look in the template PluginSource.cpp, you'll see from the comments that there are at least two types of custom function you can define: // Such C functions must match one of the following patterns: // 1. int <function_name:><ktc_tree_t node> // or // 2. ktc_tree_t <function name> <ktc_tree_t node> // If you want to implement a boolean custom predicate, use the first pattern; // 0 must be returned for false, and a non-zero value for true. The first type of function, a custom predicate, simply checks whether something about the incoming KAST node is true, and returns 1 if it's true, or zero otherwise. The second type is a getter function and retrieves a node from the KAST tree and returns it to the KAST expression (presumably for further processing). In the context of built-in functions, we can see that functions like: isClassMember() isVirtual() conform to the predicate pattern, and functions like getParent() getReturnType() conform to the getter pattern. (Although the built-in KAST functions use a suggestive naming convention, there is no absolute requirement that custom functions follow this convention.) A third type of function that you can write returns a string. This type of function will be covered in Example 2. For simplicity we're going to use the custom predicate function type. Edit the template PluginSource.cpp and replace its content with the following: #include <stdio.h> #include <XPath_plugins.h> #include <ktcAPI.h> int helloWorld(ktc_tree_t node) { fprintf(stderr, "Hello world\n"); return 1; } HOOKS_SET_START XPath_register_int_hook("helloWorld", helloWorld); HOOKS_SET_END Now you have created a custom KAST function and a checker to execute it.
Executing and testing your custom functionYou can execute and test your custom function by running 'make' (assuming you modified the Makefile as described above). The final output of 'make' should display one warning message for the one invocation of the 'helloWorld()' custom function in the testcase.cc code. The Klocwork build process redirects stderr to the build log file, so the upbeat "Hello world" message will be displayed in the build log file, which you can find in TUTORIAL/.kwlp/workingcache/tables . You should take care not to use stdout for debug messages, as these will cause protocol errors for checkers deployed to On-the-fly analysis desktops, such as Visual Studio. |