In this section:
Introduction
In most cases, the commands and node properties shipped with RuleWizard are sufficient to help you build coding patterns you want to identify. There may be cases, however, when the predefined components are unable to represent the exact pattern you want to identify or express the exact action you want performed when a given pattern is identified. In these cases, you can use a script to customize rules.
You can add pieces of code to the rule definition to provide a highly customizable definition of the pattern enforced by the rule. Unlike predefined blocks, scripts invoked from inside the rules can access the current context of the rule (such as visited function, variable, scope, etc.). You can design a script to perform any specific function.
Scripting components are referred to as Methods in RuleWizard. Methods can be added to your rule to act as a node within the rule or to act on the output of another node. Methods can be written in CPython, Java, Jython, and JavaScript. They can take zero, one, or two arguments. The first argument, if provided, is always a value passed from the node to which it is attached. The second argument can provide contextual information about the file that you are testing.
Adding Scripted Components
After creating a rule in the RuleWizard GUI, you can add scripted components to the rule definition. Parasoft static analysis will execute the script when the associated rule component is traversed. Scripts can be added to rule definitions as an output component or as a separate node.
When adding scripts as an output component, the scripts can issue a violation method if the rule is not adhered to.
When added as a separate node, scripts can control the behavior of the entire rule by returning a value of 1 (one) to indicate a violation, or by returning a value of 0 (zero) to indicate conformance to the verified rule.
- Right-click on a node and choose one of the following:
- Create Output> Method. This will add a script as a rule node.
- Create Method> Boolean or Node. This will add a script as an output component.
Boolean Methods will be added as a child component that returns a Boolean value. The method will take a node argument corresponding to its parent. For example, if a Boolean Method Component is a child of a String Component, the node argument passed to the method is a string. This has similar functionality to the Output Component when it is configured for a Method.
Node Methods return a node that is passed on to its children. The top portion of the node will be the name of the method set for that component, and the bottom portion will list the types that the component acts on.
- Choose a language from the Language drop-down menu and define the script to be implemented in the Implementation box. You can use an existing file as the source of code for your method or you can create the method within RuleWizard.
- To use an existing file, enable File option and browse for the script file.
- To write the Method in RuleWizard, enable the Text option and enter your code in the text field.
- Choose the appropriate argument from the Method drop-down list. This list will be composed of any definitions contained in your script. Since a script can contain multiple arguments you can select the one that you want to use in this method.
- Click OK. The method is now ready to be executed with your rule.
You can add as many methods to your rule as you wish. Each time a Method node is processed, the specified code will be invoked to either provide rule output or process information from the current rule context.
If the method is used as an output component, the rule will be considered as valid and marked as yellow once the code is provided in the output component. RuleWizard assumes that the code will provide some output for the rule.
Checking the Script
To check that the specified script is valid and runnable (or to add method entries to the Method box), right-click the File or Text text field (click whichever one you used to specify your script) and choose Evaluate from the shortcut menu.
Method Requirements
A rule can have any number of nodes using scripts. The methods should meet the following conditions.
Arguments | Methods should have zero, one, or two arguments. The first argument, if provided, is a Example (Jython method signatures):
As the rule is traversed, it is matched to the parse tree of the source file. The node argument above is a The |
---|---|
Method names | There is no restriction on method names. |
Boolean method return values | Boolean methods should either return 1 to indicate a violation or 0 to indicate conformance to the condition being verified. |
Method implementation | Method implementation must be valid CPython, Jython, JavaScript, or Java code (indentation must be correct). If an error is detected in an output method, the output symbol will become red to indicate that the code is incorrect. |
Hand-written scripts | If the script was entered in the text box of the Customize Method dialog, the rule must be saved every time the script is modified. |
Language-specifc Information
Java | When you specify a Java class in any of the scripting Class fields, you must specify a compiled class that is on your classpath. If the class you are using is part of a package, you need to specify the complete package name as well as the class name (for example, |
---|---|
JavaScript | JavaScript Methods can call Java classes and methods that are on the classpath. The RuleWizard JavaScript emulation is based on FESI. For details on FESI, visit http://home.worldcom.ch/~jmlugrin/fesi/ |
Python/Jython | RuleWizard supports the Jython implementation of Python. Jython is an implementation of Python that is integrated with Java. For information on Jython, including information on how to write Jython and also how to invoke Java classes from inside Jython, visit http://www.jython.org. You need to ensure that the directory which contains the script is on the Python path. |
Advanced Scripting for C/C++
RuleWizard supports additional scripting options for C and C++.
Primary API Modules
You can use RuleWizard’s C/C++ API for Python scripting. Before you start working with this API, we recommend that you become familiar with the following three API modules:
NodeProvider
This module functions as a wrapper for the node from which the Python script is invoked. Depending on the node, various sets of properties are available.
RuleContext
Provides access to the current rule context. For example, RuleContext allows the following:
- Obtain content of a collector as a list using
context.getList (“A”)
where“A”
is the label of the collector. - Generate an error message by calling
context.report (“Violation detected”)
where“Violation detected”
will appear in the message body when the violation is reported.
EnforcerContext
Allows for the use of Cross-Rules where one C++ or C++ Text rule can invoke another C++ Text rule from within Python scripts.
Cross-rules
Cross-rules enable you to call existing text rules from within a Python script embedded in another C++ or Text rule. This allows you to combine multiple rules with some basic functionality into a single rule that enforces more complex patterns.
To create a Cross-rule, add a Python script as described in #Adding Scripted Components and insert the code to invoke the rule in the Text box of the Customize Method dialog box.
Invoke rules using the RuleEnforcerContext
instance (accessible via the second argument of a Python method) by calling the executeRule()
method of the enforcer. The executeRule()
method must pass two arguments:
- The name of the rule to invoke.
- The node passed to the Python method calling the rule.
The executeRule()
method returns 1
(one) if the invoked text rule detected any violations, and 0
(zero) otherwise. Use this return value to alter the flow of control in your Python method.
For example, you can enter the following code as a cross-rule:
def somePythonMethod(node, context): # ... # invoke here the "lower lever" text rule: parent = context.getParentContext() result = parent.executeRule("./my_text.rule", node) # my_text.rule was executed and the result # specifies whether any violation was detected if 1 == result: # my_text.rule reported violation else: # my_text.rule did not detect any violations # ...
Advanced Scripting for Java
Jython is an implementation of Python that is integrated with Java. RuleWizard’s API for Java allows you to add Jython code to the rule definition to ensure maximum flexibility in customizing the patterns enforced by the rules. You can change the rule pattern to specify any number of violations, as well as collect, process and save data.
Using RuleWizard’s API for Java gives you numerous possibilities, which include:
- Adding
1
to the parameter number shown in the violation message to display parameters starting with1
(by default, the count starts at0
). - Reporting an error for variables that have been collected by collectors and differ only by one "
_
" character. - Operating on collectors to detect variables that are not declared in alphabetical order.
- Writing messages to the system console so that the CI server can show the build status before the build finishes.
- Using data collected with other tools. For example, an Excel file can be exported to CVS and used when the rule is executed. The data collected in the process can be used to generate a script to exclude some results.
- Saving data to a text file so that it can be further processed with other software.
Definition
The definition of your Jython method should contain two arguments:
def check(node, context):
The node
argument represents the node where the Jython script runs. The context
argument represents the RuleWizard framework that can be used to report violations.
Any name can be used for the method name.
Node
The following node arguments are supported.
Node | Description |
---|---|
node.getFileName() | Returns the source file name |
node.getFilePath() | Returns the path to the file |
node.getFileContent() | Returns the content of the file |
node.getNodeContent() | Returns the content of the node |
node.getStartColumn() | Returns the start column of the node in the source file |
node.getEndColumn() | Returns the end column of the node in the course file |
node.getStartLine() | Returns the start line of the node in the source file |
node.getEndLine() | Returns the end line of the node in the source file |
Context
The following context arguments are supported.
Context | Description |
---|---|
context.report(String message) | Reports a triggered by the current node |
context.get(String) | Gets a value stored in the context |
context.put(String,String) | Stores a value in the context. Can be used to transfer information between scripts in a rule |
context.getKeys() | Gets a list of keys stored in the context |
context.getCollection(String collectorLabel) | Allows you to operate on collected elements in the RuleWizard collector. Returns a collection of nodes |
Example Usage
def check(node, context): print "Number of collected elements:" + str(len(context.getCollection("A"))) for x in context.getCollection("A"): print x print "---" return 1
Example Scenario
The print
method writes messages to the Jtest console. In the example below, an occurrence of the node will print all the methods from this node to the console and report a violation.
def check (node, context): print "filename: " + node.getFileName() print "content file: " + node.getFileContent() print "node content: " + node.getNodeContent() print "start column: " + str(node.getStartColumn()) print "start line: " + str(node.getStartLine()) print "end column: " + str(node.getEndColumn()) print "end line: " + str(node.getEndline()) context.report("Line " +str(node.getStartLine()) + " from " + node.getFileName() + " contains 'if' statement") return 1