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