#This script is designed to run with Understand - CodeCheck
use base ("Understand::Codecheck");
use strict;


use constant MULT => 'Multiple exit points from function';
use constant NOEXIT => 'No exit point in function';
use constant NOTEND => 'Exit point not at end of function';


sub register_tr_text() {
  my $check = shift;
  $check->add_tr_text(MULT);
  $check->add_tr_text(NOEXIT);
  $check->add_tr_text(NOTEND);
}

sub name { return "14.7 A function shall have a single point of exit at the end of the function";}

sub description { return "14.7 (Required) A function shall have a single point of exit at the end of the function.";}

sub detailed_description { return <<"END_DESC"
This is required by IEC 61508, under good programming style.
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");
  my @funcEnds =$file->filerefs("end","function");
  return unless @funcEnds;
  
  my $lexer = $file->lexer;
  return unless $lexer;
  
  #Start at the end of the function and walk through it backwards;
  FUNCTIONLOOP:foreach my $funcEnd (@funcEnds){
    my $start = $funcEnd->ent->ref("definein");
    my $atEnd = 0;
    my $statementCount;
    my $exitCount;
    my $lexeme = $lexer->lexeme($funcEnd->line,$funcEnd->column);
    while($lexeme && $lexeme->line_begin >= $start->line){
      $exitCount++ if $lexeme->token eq "Keyword" && $lexeme->text =~ /Exit|return|goto/i;
      $statementCount++ if $lexeme->token eq "Punctuation" && $lexeme->text =~ /[;}]/;
      if ($statementCount && $statementCount == 2 && $exitCount){
        $atEnd = 1;
      }
    }continue{
      $lexeme=$lexeme->previous;
    }
    if ($exitCount && $exitCount > 1){
      $check->violation($funcEnd->ent,$file,$start->line,$start->column,MULT);
    }elsif(! $exitCount && $funcEnd->ent->type ne "void"){
      $check->violation($funcEnd->ent,$file,$start->line,$start->column,NOEXIT);
    }elsif($exitCount==1 && ! $atEnd){
      $check->violation($funcEnd->ent,$file,$start->line,$start->column,NOTEND);
    }
  }
  
 
  
  # $check->violation($entity,$file,$line,$column,ERR1,%1,%2);  # the %1 and %2 are optional parameters
  # $check->violation(0,0,-1,-1,ERR1,%1,%2)  #if no entity or location
  
  #my $optionVal = $check->option->lookup($name);
}