主要内容

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 if statement does not have a braced compound statement.

  • The opening brace of the compound statement is not placed on the same line as the if condition.

The workflow demonstrates how to:

  • Analyze the syntactic structure of if statements

  • Implement 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.

  • startLine and endLine — 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;
  //...
}

}
The syntaxes of these 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 statementNoncompliant if statement with no bracesNoncompliant if statement with brace on the next line
Code
void foo (bool cond){
  int x;
  if(cond==true){
  x = 0;
  }
}
void foo (bool cond){
  int x;
  if(cond==true)
  x = 0;
}
void foo (bool cond){
  int x;
  if(cond==true)
  {
  x = 0;
  }
}
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_statement node does not have a compound_statement child node.

  • The if_statement node contains a compound_statement and the start line of the compound_statement is not equal to the end line of the condition_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 ifnode by using the query Cpp.IfStatement.is(&ifnode). The object ifnode is an object of type Cpp.IfStatement.IfStatement.

  • Retrieve the child node of if statements and store them in child by using the query ifnode.getAChild(&child). The object child is a generic Node.

  • Check if a child node is a CompoundStatement type object by using the query Cpp.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)
}
Then, define a defect 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 if statements in your code and store them in ifnode by calling Cpp.IfStatement.is(&ifnode). The object ifnode is an object of type Cpp.IfStatement.IfStatement.

  • From the retrieved if statements, find the if statements that have compound statements using the predicate hasCompoundStatement defined in the preceding section.

  • Retrieve the child nodes of the filtered if statements and store the output in child by calling Cpp.IfStatement.getAChild(&child)

  • Retrieve the line where the condition clause end. Create a new predicate for this purpose getOpeningBraceLine that uses the predicate Cpp.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)
}
This predicate queries for all child nodes of the 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:

  •  SyntaxDefect/If_Statement/ImproperBraceforifStatement.pql

  •  SyntaxDefect/If_Statement/hasCompoundStatement.pql

  •  SyntaxDefect/If_Statement/getOpeningBraceLine.pql

  •  SyntaxDefect/If_Statement/getConditionEndLine.pql

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 SyntaxDefect/main.pql, insert the rule into a coding standard:

package main

catalog TestStandard = {
#[Description("Test Section")]
	section TestSection = {
        If_Statement.TestRule
       
	}

}

Package this code into a standard:
polyspace-query-language package
Then, copy this code in 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;
}
Run a test to verify the user-defined coding rule reports violations as expected:
polyspace-query-language test example.cpp
The command line outputs:
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
This indicates that the user defined defects flag the if statements with both noncompliant syntaxes.

See Also

Topics

External Websites