#This script is designed to run with Understand - CodeCheck use base ("Understand::Codecheck"); use strict; use constant ERR1 => 'Macro %1 is defined within a block'; use constant ERR2 => 'Macro %1 is undefined within a block'; sub register_tr_text() { my $check = shift; $check->add_tr_text(ERR1); $check->add_tr_text(ERR2); } sub name { return "16-0-2 Macros shall only be #define'd or #undef'd in the global namespace";} sub description { return "16-0-2 (Required) Macros shall only be #define'd or #undef'd in the global namespace";} sub detailed_description { return <<"END_DESC"
Rationale
While it is legal to place #define or #undef directives anywhere in a source file, placing them outside
of the global namespace is misleading as their scope is not restricted. This may be inconsistent
with developer expectations.
See also Rule 16-0-3
Example
#ifndef MY_HDR
#define MY_HDR // Compliant
namespace NS
{
#define FOO // Non-compliant
#undef FOO // Non-compliant
}
#endif
END_DESC
}
sub test_language {
my $language = shift;
return $language =~ /C\+\+/; #Handles C and C++
}
sub test_entity { return 1;}
sub test_global { return 0;}
sub define_options{}
sub check {
my $check = shift;
my $file = shift;
return unless $file->kind->check("file ~unknown ~unresolved");
return unless $file->filerefs("","macro");
my $lexer = $file->lexer;
return unless $lexer;
my $findEnt = 0;
foreach my $lexeme ($lexer->lexemes()) {
if ($lexeme->text =~ /^undef$|^define$/i && $lexeme->token eq "Preprocessor"){
$findEnt = $lexeme->text;
}elsif($findEnt && $lexeme->ref){
my $err = $findEnt =~ /define/?ERR1:ERR2;
$check->violation($lexeme->ent,$file,$lexeme->line_begin,$lexeme->column_begin,$err,$lexeme->ent->name) if $lexeme->ref->ent->id != $file->id;
$findEnt=0;
}
}
}