Example 2: Modifying error messages
In this example, we'll modify the TUTORIAL checker to display a relevant checker message with the context of the source it's analyzing. To achieve this, we'll use a set of reserved KAST variables, $0 .. $9, which can be placed in checker messages using the notation {0} .. {9}. Using these numbered parameters, we'll modify the message attribute of the error element of our checker: <error id="TUTORIAL" enabled="true" severity="3" title="Function Definition" message="Called on function {0}()"> <pattern> // FuncDef [ $0 := getMyText() ] </pattern> </error> The assignment to $0 in the KAST expression will be reflected through the {0} parameter in the checker message. All that remains is to code a custom function that returns an appropriate string for storage in the $0 variable: #include <stdio.h> #include <XPath_plugins.h> #include <ktcAPI.h> ktc_string_t getMyText(ktc_tree_t node) { return ktc_string_new("foo"); } HOOKS_SET_START XPath_register_string_hook("getMyText", getMyText); HOOKS_SET_END Exercise this modified checker, using 'make', and the output should read: 1 (Local) ./TUTORIAL/testcase.cc:1 TUTORIAL (3:Warning) Analyze Called on function foo(). Summary: 1 Local 1 Total Issue(s) Having a hardcoded function name isn't much real use, so let's extend this to retrieve the name of the function from the node passed in (which will be a FuncDef node based on our KAST expression). To access things like names and types, we need to interrogate the semantic information of the node, not the node itself. Modify the implementation of getMyText(): ktc_string_t getMyText(ktc_tree_t node) { ktc_semanticInfo_t si = ktc_getSemanticInfo(node); return ktc_string_new(ktc_sema_getIdentifier(si)); } Now when you execute the test case, the output should include the name of the first function in the test case, which is 'test': 1 (Local) ./TUTORIAL/testcase.cc:1 TUTORIAL (3:Warning) Analyze Called on function test(). Summary: 1 Local 1 Total Issue(s)
Adding a check for appropriate contextNow that we're in the semantics domain, we'll extend our checker definition to call our function from if() statements as well as function definition nodes. Since if() statements don't have names, we can't use the same technique as we did for the function definitions. Instead, we can restrict our custom function so that it works only in surroundings it's expecting: ktc_string_t getMyText(ktc_tree_t node) { ktc_semanticInfo_t si = ktc_getSemanticInfo(node); return ktc_sema_isFunction(si) ? ktc_string_new(ktc_sema_getIdentifier(si)) : ktc_string_new("** invalid **"); } Add a new pattern element to the checker definition for the if() statement: <error id="TUTORIAL" severity="3" title="Function Definition" message="Called on function {0}."> <pattern> // FuncDef [ $0 := getMyText() ] </pattern> <pattern> // IfStmt [ $0 := getMyText() ] </pattern> </error> Now the output from testcase.cc will look like: 1 (Local) ./TUTORIAL/testcase.cc:1 TUTORIAL (3:Warning) Analyze Called on function test(). 2 (Local) ./TUTORIAL/testcase.cc:3 TUTORIAL (3:Warning) Analyze Called on function ** invalid **(). Summary: 2 Local 2 Total Issue(s) |