Detect Syntactic Issues Using Polyspace Query Language Syntactic Classes
Syntactic issues occur when the relative positions of syntax elements in your C/C++ code do not follow the intended style or structure. Such issues can lead to unexpected program behavior, even when the code is syntactically valid.
Using Polyspace Query Language (PQL), define user‑defined defect checkers that detect these issues by querying the syntax tree. This example shows how to create a user‑defined coding rule that identifies two types of noncompliant if statement syntax:
The
ifstatement does not have a braced compound statement.The opening brace of the compound statement is not placed on the same line as the
ifcondition.
The workflow demonstrates how to:
Analyze the syntactic structure of
ifstatementsImplement helper predicates for tree navigation.
Create defects corresponding to each noncompliant case.
Package the defects into a user‑defined coding standard.
Test the rule on sample C++ source code.
Relevant Syntax Nodes
During analysis, Polyspace parses your source code into a syntax tree. For this topic, the relevant syntax nodes include:
You query these nodes using PQL predicates. This topic uses these predicates:
is— Retrieve nodes of a given type.getAChild— Retrieve a child node.cast()— Cast a generic node to a specific syntactic node.startLineandendLine— Retrieve source line information.
Define Issue
Define the precise syntax that you want to allow and the syntaxes you want to disallow.
This topic creates a user-defined syntactic defect that is reported when the opening brace
following the condition of an if statement is not in the same line as the
condition. For example, the syntax of this if statement is compliant with
the rule:
void foo (bool cond){
int x;
if(cond==true){ //Compliant
x = 0;
//...
}
}if statements are
noncompliant:void foo(bool cond) {
x = 1;
if(cond == true) //Noncompliant
x = 0;
if(cond == true) //Noncompliant
{
x = 0;
//....
}
}Compare Syntax Nodes of Compliant and Noncompliant Syntax
To differentiate the compliant syntax and the noncompliant syntaxes, compare the syntax trees generated for the syntaxes by a tool such as Tree-sitter:
Compliant if statement | Noncompliant if statement with no braces | Noncompliant if statement with brace on the next
line | |
|---|---|---|---|
| Code |
|
|
|
| Syntax tree |
translation_unit [0, 0] - [6, 0]
function_definition [0, 0] - [5, 1]
type: primitive_type [0, 0] - [0, 4]
declarator: function_declarator [0, 5] - [0, 20]
declarator: identifier [0, 5] - [0, 8]
parameters: parameter_list [0, 9] - [0, 20]
parameter_declaration [0, 10] - [0, 19]
type: primitive_type [0, 10] - [0, 14]
declarator: identifier [0, 15] - [0, 19]
body: compound_statement [0, 20] - [5, 1]
declaration [1, 2] - [1, 8]
type: primitive_type [1, 2] - [1, 5]
declarator: identifier [1, 6] - [1, 7]
if_statement [2, 2] - [4, 3]
condition: condition_clause [2, 4] - [2, 16]
value: binary_expression [2, 5] - [2, 15]
left: identifier [2, 5] - [2, 9]
right: true [2, 11] - [2, 15]
consequence: compound_statement [2, 16] - [4, 3]
expression_statement [3, 2] - [3, 8]
assignment_expression [3, 2] - [3, 7]
left: identifier [3, 2] - [3, 3]
right: number_literal [3, 6] - [3, 7] |
translation_unit [0, 0] - [5, 0]
function_definition [0, 0] - [4, 1]
type: primitive_type [0, 0] - [0, 4]
declarator: function_declarator [0, 5] - [0, 20]
declarator: identifier [0, 5] - [0, 8]
parameters: parameter_list [0, 9] - [0, 20]
parameter_declaration [0, 10] - [0, 19]
type: primitive_type [0, 10] - [0, 14]
declarator: identifier [0, 15] - [0, 19]
body: compound_statement [0, 20] - [4, 1]
declaration [1, 2] - [1, 8]
type: primitive_type [1, 2] - [1, 5]
declarator: identifier [1, 6] - [1, 7]
if_statement [2, 2] - [3, 8]
condition: condition_clause [2, 4] - [2, 16]
value: binary_expression [2, 5] - [2, 15]
left: identifier [2, 5] - [2, 9]
right: true [2, 11] - [2, 15]
consequence: expression_statement [3, 2] - [3, 8]
assignment_expression [3, 2] - [3, 7]
left: identifier [3, 2] - [3, 3]
right: number_literal [3, 6] - [3, 7] |
translation_unit [0, 0] - [7, 0]
function_definition [0, 0] - [6, 1]
type: primitive_type [0, 0] - [0, 4]
declarator: function_declarator [0, 5] - [0, 20]
declarator: identifier [0, 5] - [0, 8]
parameters: parameter_list [0, 9] - [0, 20]
parameter_declaration [0, 10] - [0, 19]
type: primitive_type [0, 10] - [0, 14]
declarator: identifier [0, 15] - [0, 19]
body: compound_statement [0, 20] - [6, 1]
declaration [1, 2] - [1, 8]
type: primitive_type [1, 2] - [1, 5]
declarator: identifier [1, 6] - [1, 7]
if_statement [2, 2] - [5, 3]
condition: condition_clause [2, 4] - [2, 16]
value: binary_expression [2, 5] - [2, 15]
left: identifier [2, 5] - [2, 9]
right: true [2, 11] - [2, 15]
consequence: compound_statement [3, 2] - [5, 3]
expression_statement [4, 2] - [4, 8]
assignment_expression [4, 2] - [4, 7]
left: identifier [4, 2] - [4, 3]
right: number_literal [4, 6] - [4, 7] |
After comparing the syntax trees of compliant and noncompliant code, there are two situations when the rule is violated:
The
if_statementnode does not have acompound_statementchild node.The
if_statementnode contains acompound_statementand the start line of thecompound_statementis not equal to the end line of thecondition_clause.
Each of these can be implemented as a separate defect that together constitute one coding rule. By splitting these noncompliant situations into separate defects, you can report specific messages tailored for each situation.
Detect Noncompliant if Statement with No Braces
Use the predicates of the class IfStatement to
detect whether an if statement has a child node that is a CompoundStatement object. For example:
Retrieve all if statements in the code and store them in
ifnodeby using the queryCpp.IfStatement.is(&ifnode). The objectifnodeis an object of typeCpp.IfStatement.IfStatement.Retrieve the child node of if statements and store them in
childby using the queryifnode.getAChild(&child). The objectchildis a genericNode.Check if a child node is a
CompoundStatementtype object by using the queryCpp.CompoundStatement.isa(child).
To translate the preceding algorithm into PQL code, construct a predicate
hasCompoundStatement that implements the core logic of checking for
compound statement. This predicate accepts Cpp.IfStatement.IfStatement
node and checks for a child compound
statement:
predicate hasCompoundStatement(Cpp.IfStatement.IfStatement &ifnode) {
return
ifnode.getAChild(&child) and
Cpp.CompoundStatement.isa(child)
}DoesNotHaveCompoundStatement that
reports when an if statement lacks a compound
statement:defect DoesNotHaveCompoundStatement = when Cpp.IfStatement.is(&ifnode) and not hasCompoundStatement(ifnode) raise "If statement does not have a following compounding statement" on ifnode
Noncompliant if Statement with Brace on Next Line
If an if statement contains a compound statement, the opening curly
brace of the compound statement must be on the same line as the ending of the
if statement. To detect violations of this syntax rule, detect whether
the opening curly brace occurs on the same line as the if condition.
Find all
ifstatements in your code and store them inifnodeby callingCpp.IfStatement.is(&ifnode). The objectifnodeis an object of typeCpp.IfStatement.IfStatement.From the retrieved
ifstatements, find theifstatements that have compound statements using the predicatehasCompoundStatementdefined in the preceding section.Retrieve the child nodes of the filtered if statements and store the output in
childby callingCpp.IfStatement.getAChild(&child)Retrieve the line where the condition clause end. Create a new predicate for this purpose
getOpeningBraceLinethat uses the predicateCpp.ConditionClause.endLine.Retrieve the line where the compound statement begins. Create a new predicate for this purpose that uses
Cpp.ConditionClause.startline.Report a defect if the two retrieved line numbers are unequal.
Construct a predicate getOpeningBraceLine that retrieves the line
number for the opening brace of the compound statement in the if
statement:
predicate getOpeningBraceLine(Cpp.IfStatement.IfStatement ifnode, Lang.Unsigned &pos ){
return
ifnode.getAChild(&child) and
Cpp.CompoundStatement.cast(child, &cs)
and cs.startLine(&pos)
}IfStatement. Then, it filters the child nodes to separate out the
compound statements using the predicate Cpp.CompoundStatement.cast(child,
&cs). Finally, it retrieves the line at which the child compound statement
begins by using Cpp.CompoundStatement.startLine.Similarly, construct a predicate getConditionEndLine that retrieves
the line at which the condition clause of the if statement
ends:
predicate getConditionEndLine(Cpp.IfStatement.IfStatement ifnode, Lang.Unsigned &pos ){
return
ifnode.getAChild(&child) and
Cpp.ConditionClause.cast(child, &cc)
and cc.endLine(&pos)
} By using these predicates, create the defect
ImproperBraceforifStatement, which reports a violation when the opening
brace of an if statement is not on the same line as the
condition:
defect ImproperBraceforifStatement = when Cpp.IfStatement.is(&ifnode) and hasCompoundStatement(ifnode) and getOpeningBraceLine(ifnode, &line) and getConditionEndLine(ifnode, &endConditionLine) and not line == endConditionLine raise "If statement condition and opening brace must be on the same line" on ifnode
Implement User-Defined Coding Rule
To implement the coding rule, initialize a new user-defined coding standard by running
this command at the command line in the folder
SyntaxDefect:
polyspace-query-language init
Copy the predicates into their own files:
Combine the predicates and defects into a rule in
:SyntaxDefect/If_Statement/TestRule.pql
package If_Statement
#[Description("If statement rules"), Id(TestRule)]
rule TestRule = {
DoesNotHaveCompoundStatement,
ImproperBraceforifStatement
}In , insert the rule
into a coding standard:SyntaxDefect/main.pql
package main
catalog TestStandard = {
#[Description("Test Section")]
section TestSection = {
If_Statement.TestRule
}
}
polyspace-query-language package
example.cpp:void foo (bool cond){
int x;
if(cond==true){ // expect-0-TestRule
x = 0;
}
}
void foo1 (bool cond){
int x;
if(cond==true) // expect-1-TestRule
{
x = 0;
}
}
void foo2 (bool cond){
int x;
if(cond==true) // expect-1-TestRule
x = 0;
}polyspace-query-language test example.cpp
number of actual defects: 2 number of expected annotations: 3 (including 1 expected absence of defects). _______________________________________________ Checking expected defects with actuals... ----------------------------------------- _______________________________________________ Looking for unexpected defects... --------------------------------- _______________________________________________ Tests passed
if statements with both noncompliant syntaxes.See Also
Topics
- Polyspace Query Language Syntax for Creating User-Defined Defects
- Overview of Syntactic Classes in Polyspace Query Language
- Choose Between Semantic and Syntactic Classes
- Implement Exceptions in User-Defined Defects
- Unit Test User-Defined Defects
