#This script is designed to run with Understand - CodeCheck use base qw(Understand::Codecheck); use strict; use Codecheck::Libraries::InfoSiftr qw(resolveTypedefs); use constant MAX_NUM => 2; use constant ERR1 => 'Violation: object "%1" includes more than ' . MAX_NUM . ' levels of indirection (%2 levels).'; sub register_tr_text { my $check = shift; $check->add_tr_text(ERR1); } sub name { '5-0-19 No more than 2 levels of indirection.' } sub description { '5-0-19 (Required) The declaration of objects should contain no more than 2 levels of pointer indirection.' } sub detailed_description { <<'END_DESC'

Rationale
Use of more than two levels of indirection can seriously impair the ability to understand the behaviour of the code, and therefore should be avoided.

Example
typedef int8_t * INTPTR;
struct s { 
   int8_t *   s1;           // Compliant 
   int8_t **  s2;           // Compliant 
   int8_t *** s3;           // Non-compliant 
};
struct s *   ps1;           // Compliant 
struct s **  ps2;           // Compliant 
struct s *** ps3;           // Non-compliant
int8_t **  (  *pfunc1)();   // Compliant 
int8_t **  ( **pfunc2)();   // Compliant 
int8_t **  (***pfunc3)();   // Non-compliant 
int8_t *** ( **pfunc4)();   // Non-compliant
void function( int8_t *   par1,                // Compliant 
               int8_t **  par2,                // Compliant 
               int8_t *** par3,                // Non-compliant 
               INTPTR *   par4,                // Compliant 
               INTPTR *   const * const par5,  // Non-compliant 
               int8_t *   par6[],              // Compliant 
               int8_t **  par7[])              // Non-compliant 
{
   int8_t *   ptr1;                 // Compliant 
   int8_t **  ptr2;                 // Compliant 
   int8_t *** ptr3;                 // Non-compliant 
   INTPTR *   ptr4;                 // Compliant 
   INTPTR *   const * const ptr5;   // Non-compliant 
   int8_t *   ptr6[ 10 ];           // Compliant 
   int8_t **  ptr7[ 10 ];           // Compliant 
}
END_DESC } sub test_language { my $language = shift; return $language eq 'C++'; } sub test_entity { 0 } sub test_global { 1 } sub define_options { } sub check { my $check = shift; my %typelist; foreach my $file ($check->get_files) { my $type; foreach my $ref ($file->filerefs('declare, define', 'object, parameter, function', 0)) { if($typelist{$ref->ent->type}){ $type = $typelist{$ref->ent->type}; } else{ $type = resolveTypedefs($ref->ent->type, $check->db); $typelist{$ref->ent->type} = $type; } while ($type =~ m! \( (.*?) \) !xg) { # must be a function pointer # thus, we must handle the two significant parts separately my $contents = $1; (my $stars = $1) =~ s![^*\[]!!g; my $levels = length $stars; if ($levels > MAX_NUM) { $check->violation($ref->ent, $ref->file, $ref->line, $ref->column, ERR1, $ref->ent->longname, $levels); } $type =~ s! \( \Q$contents\E \) !!xg; } $type =~ s![^*\[]!!g; my $levels = length $type; if ($levels > MAX_NUM) { $check->violation($ref->ent, $ref->file, $ref->line, $ref->column, ERR1, $ref->ent->longname, $levels); } } } return; }