#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.
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; }