use base ("Understand::Codecheck"); use strict; use constant ERR1 => "Constructor with Single Argument is not explicit"; use constant ERR2 => "Possible Violation: Constructor with Single Argument is not explicit and not defined"; use constant { NODEFOPT => "Violations found in declared but not defined functions should be:", OPT1VIOLATION => "reported as a violation", OPT2POSSIBLE =>"reported as a possible violation", OPT3IGNORE => "ignored", }; sub register_tr_text { my $check = shift; $check->add_tr_text(ERR1); $check->add_tr_text(ERR2); } sub name { return "12-1-3 All constructors that are callable with a single argument of fundamental type shall be declared explicit"; } sub description { return "12-1-3 (Required) All constructors that are callable with a single argument of fundamental type shall be declared explicit."; } sub detailed_description { return <<"END_DEF"
Rationale
The explicit keyword prevents the constructor from being used to implicitly convert from a fundamental type to the class type.
class C
{
public:
C ( int32_t a ) // Non-compliant
{
}
};
class D
{
public:
explicit D ( int32_t a ) // Compliant
{
}
};
END_DEF
}
sub test_language {
my $language = shift;
return $language =~ /C\+\+/;
}
sub test_entity {
return 1;
}
sub test_global {
return 0;
}
sub define_options{
my $check = shift;
my @choices = [OPT1VIOLATION,OPT2POSSIBLE,OPT3IGNORE];
$check->option->radio_vert("handleDeclareOnly",NODEFOPT,@choices,OPT3IGNORE);
}
sub check {
my $check = shift;
my $file = shift;
return unless $file->kind->check("file");
my @defRefs = $file->filerefs("define","class,struct,union",1);
#Also consider functions declared in this file if they have no definition
my @declRefs = $file->filerefs("declare","class,struct,union",1);
foreach (@declRefs){
next if $_->ent->ents("definein");
push @defRefs;
}
foreach my $classRef(@defRefs){
do_one_class($check,$classRef->ent);
}
}
# check one class
sub do_one_class {
my $check = shift;
my $class = shift;
foreach my $func ($class->ents("define,declare","member function")) {
next if !checkConstructor($class,$func);
next if !checkOneArgument($func);
next if checkExplicit($func);
my $handleDeclareOnly= $check->option->lookup("handleDeclareOnly");
if (checkDefined($func) || $handleDeclareOnly eq OPT1VIOLATION) {
foreach my $ref ($func->refs("declarein,definein")) {
$check->violation($ref->ent,$ref->file,$ref->line,$ref->column,ERR1);
}
} elsif ($handleDeclareOnly eq OPT2POSSIBLE) {
foreach my $ref ($func->refs("declarein")) {
$check->violation($ref->ent,$ref->file,$ref->line,$ref->column,ERR2);
}
}
}
}
# check if func is a constructor
sub checkConstructor {
my $class = shift;
my $func = shift;
return ($class->name() eq $func->name());
}
# check if func has exactly one argument
sub checkOneArgument {
my $func = shift;
if ($func->kind->check("unresolved")) {
my $params = $func->freetext("Parameters");
return 0 if !$params;
return $params !~ m/,/;
} else {
my @ents = $func->ents("define","parameter");
return (scalar(@ents) == 1);
}
}
# check if func is explicit
sub checkExplicit {
my $func = shift;
return $func->kind->check("explicit");
}
# check if func is defined
sub checkDefined {
my $func = shift;
return $func->ents("definein");
}