#This script is designed to run with Understand - CodeCheck use base ("Understand::Codecheck"); use strict; use constant ERR1 => 'Identifier "%1" possibly hiding outer definition from line %2'; sub register_tr_text() { my $check = shift; $check->add_tr_text(ERR1); } sub name { return "2-10-2 Identifers declared in an inner scope shall not hide an identifer declared in an outer scope";} sub description { return "2-10-2 (Required) Identifers declared in an inner scope shall not hide an identifer declared in an outer scope.";} sub detailed_description { return <<"END_DESC"

Rationale
If an identifer is declared in an inner scope and it uses the same name as an identifer that already exists in an outer scope, then the innermost declaration will "hide" the outer one. This may lead to developer confusion.

The terms outer and inner scope are defned as follows: Example
  int16_t i; 
  { 
     int16_t i;   // This is a different variable 
                  // This is Non-compliant 
     i = 3;       // It could be confusing as to which i this refers 
  }
  void fn ( int16_t i )   // Non-compliant 
  {
  }
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"); my @ents = $file->filerefs("define","object,parameter",1); my %entNames; $entNames{$_->ent->name}++ for (@ents); my $useLexeme = 0; foreach (keys %entNames){ if ($entNames{$_} > 1){ $useLexeme=1; last; } } return unless $useLexeme; my $lexer = $file->lexer; return unless $lexer; my $lexeme = $lexer->first; return unless $lexeme; my @empty = (); parse_scope($file,$lexeme,$check,\@empty,\@empty); } sub parse_scope{ my ($file,$lexeme, $check, $parentVars, $paramVars) = @_; my @localVars; my $startLex = $lexeme; my $depth=1; my @parents = @{$parentVars}; my @params = @{$paramVars}; my @newParams; #First pass, find all the variables at this scope. foreach my $param(@params){ foreach my $parentRef (@parents){ if($parentRef->scope->name eq $param->ref->scope->name){ $check->violation($param->ref->scope,$param->ref->file,$param->ref->line,$param->ref->column,ERR1,$param->ref->scope->name,$parentRef->line); } } } while($lexeme && $depth >= 1){ $depth++ if $lexeme->token eq "Punctuation" && $lexeme->text eq "{"; $depth-- if $lexeme->token eq "Punctuation" && $lexeme->text eq "}"; if($depth == 1 && $lexeme->ref && $lexeme->ref->kind->check("definein") && $lexeme->ref->scope->kind->check("object")){ my $hiding =0; foreach my $parentRef (@parents){ if($parentRef->scope->name eq $lexeme->ref->scope->name){ $check->violation($lexeme->ref->scope,$lexeme->ref->file,$lexeme->ref->line,$lexeme->ref->column,ERR1,$lexeme->ref->scope->name,$parentRef->line); $hiding =1; } } push(@localVars,$lexeme->ref) unless $hiding; } $lexeme= $lexeme->next; } #second pass, go into the nested scopes recursivly push(@parents, @localVars); $lexeme = $startLex; $depth =1; while($lexeme && $depth >= 1){ if ($depth == 1 && $lexeme->ref && $lexeme->ref->kind->check("definein") && $lexeme->ref->scope->kind->check("parameter")){ push(@newParams,$lexeme); } $depth-- if $lexeme->token eq "Punctuation" && $lexeme->text eq "}"; if ($lexeme->token eq "Punctuation" && $lexeme->text eq "{"){ $lexeme = parse_scope($file,$lexeme->next,$check,\@parents,\@newParams); } $lexeme=$lexeme->next if $lexeme; } return $lexeme; }