In this section:
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.
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.
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.
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.
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. |
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. |
RuleWizard supports additional scripting options for C and C++.
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:
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.
Provides access to the current rule context. For example, RuleContext allows the following:
context.getList (“A”)
where “A”
is the label of the collector.context.report (“Violation detected”)
where “Violation detected”
will appear in the message body when the violation is reported.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 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 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 # ... |
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:
1
to the parameter number shown in the violation message to display parameters starting with 1
(by default, the count starts at 0
)._
" character.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.
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 |
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 |
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 |
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 |