#This script is designed to run with Understand - CodeCheck use base qw(Understand::Codecheck); use strict; use Codecheck::Libraries::InfoSiftr qw(getFunctionParams); use constant ERR1 => 'Violation: in function definition for "%1", parameter identifiers do not match: (%2) vs (%3)'; sub register_tr_text { my $check = shift; $check->add_tr_text(ERR1); } sub name { '8-4-2 Use the same identifier in definition and declaration of functions.' } sub description { '8-4-2 (Required)The identifiers used for the parameters in a re-declaration of a function shall be identical to those in the declaration.' } sub detailed_description { <<'END_DESC'
Rationale
The name given to a parameter helps document the purpose of the parameter within the function
body. If a function parameter is renamed in a subsequent re-declaration, then having different
names for the same object will probably lead to developer confusion.
Note that the rule also applies to any overriding set.
Exception
It is not a violation of this rule if the declaration or re-declaration contains an unnamed parameter.
// File1
void CreateRectangle ( uint32_t Height, uint32_t Width );
// File2
// Non-compliant
void CreateRectangle ( uint32_t Width, uint32_t Height );
void fn1 ( int32_t a );
void fn2 ( int32_t );
void fn1 ( int32_t b ) // Non-compliant
{
}
void fn2 ( int32_t b ) // Compliant
{
}
END_DESC
}
sub test_language {
my $language = shift;
return $language eq 'C++';
}
sub test_entity { 1 }
sub test_global { 0 }
sub define_options { }
sub getIdentifier {
my $check = shift;
my $rawParam = shift;
my @tokens = grep { # filter out '...' and 'void'
$_->{token} ne 'Punctuation'
&& $_->{text} ne 'void'
} @$rawParam;
return undef unless @tokens;
@tokens = grep { $_->{token} eq 'Identifier' } @tokens;
if (@tokens && $check->db->lookup($tokens[0]->{text}, 'typedef, enum, struct, class, union, macro', 1)) {
my $trash = shift @tokens; # weed out named types, like typedefs, enums, structs, classes
}
return undef unless @tokens;
return join ' ', map { $_->{text} } @tokens;
}
sub check {
my $check = shift;
my $file = shift;
return unless $file->kind->check('file');
my $lexer = $file->lexer(0);
return unless $lexer;
foreach my $ref ($file->filerefs('declare', 'function', 0)) {
my $defRef = (grep { $ref->ent->uniquename eq $_->ent->uniquename } $file->refs('define', 'function'))[0];
next unless $defRef;
my @params = getFunctionParams($ref, $lexer, 0);
my @rawParams = getFunctionParams($ref, $lexer, 1);
my @defParams = getFunctionParams($defRef, $lexer, 0);
my @defRawParams = getFunctionParams($defRef, $lexer, 1);
if (@params != @defParams) {
next;
}
my @badParams;
my @badDefParams;
for (my $i = 0; $i < @params; ++$i) {
my $param = $params[$i];
my $rawParam = $rawParams[$i];
my $defParam = $defParams[$i];
my $defRawParam = $defRawParams[$i];
my $identifier = getIdentifier($check, $rawParam);
my $defIdentifier = getIdentifier($check, $defRawParam);
if (!defined $identifier && !defined $defIdentifier) {
next; # if we have no identifier on either side, we'll consider that legit and "equal"
}
unless (
defined $identifier
&& defined $defIdentifier
&& $identifier eq $defIdentifier
) {
push @badParams, $param;
push @badDefParams, $defParam;
}
}
if (@badParams) {
$check->violation($ref->ent, $ref->file, $ref->line, $ref->column, ERR1, $ref->ent->longname, join(', ', @badParams), join(', ', @badDefParams));
$check->violation($defRef->ent, $defRef->file, $defRef->line, $defRef->column, ERR1, $defRef->ent->longname, join(', ', @badParams), join(', ', @badDefParams));
}
}
return;
}