#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" <p><b>Rationale</b><br> 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.</p> <p>See also Rule 16-0-3</p> <b>Example</b><pre style="margin-top:0;padding-top:0;"> #ifndef MY_HDR #define MY_HDR // Compliant namespace NS { #define FOO // Non-compliant #undef FOO // Non-compliant } #endif </pre> 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; } } }