.NAME Raise of exceptions

.DESCRIPTION
	Exceptions shall be raised only after start-up and 
before termination of the program. 

.COMMENT V7.0

.SEVERITY Required

.COMMENT
Please refer to the MISRA C++:2008 document for further details (www.misra-cpp.com)

.COMMAND tcl

.CODE

::logiscope::include -once common utilities.tcl

proc compute {standardName tree} {
  variable CurrentParameterList
  # Check all ... nodes
  utilities::filterTree $tree [list [namespace current]::check]
}

proc check { node } {
  set curOperator [::logiscope::treeOperator $node]
  set curOperatorName [::logiscope::opName $curOperator]
  # Look for a throw
  if {[string equal $curOperatorName throw]} {
    set isDestructor 0
    # Then look for the function in which the throw is called: is it a constructor or a destructor?
	# First get the function definition node
	set fctDefNode [lookForAncestor $node fndef]
	# Check if the function is a destructor
	set isDestructor [isFunctionDestructor $fctDefNode]
	# If the function is a destructor, the rule is violated
	if {[expr $isDestructor == 1]} {
	  ::logiscope::addViolation $node
	  return 0
	}
	# If the function is not a destructor, we have to check if it's a constructor
	# First we need to get the class name
	set className [lookForClassName $fctDefNode]
	# If the function identifier matches the class name, the rule is violated
	set fctName [getFunctionName $fctDefNode]

	if {[string equal $className $fctName]} {
	  ::logiscope::addViolation $node
	  return 0
	}
	
  }
  
  return 1
}

# This procedure parses the tree upwards until a given node is found for the first time
proc lookForAncestor {node ancestorName} {
  set curOperator [::logiscope::treeOperator $node]
  set curOperatorName [::logiscope::opName $curOperator]
  # If the current node is the tree root, stop the recursion
  if {[expr [::logiscope::treeRank $node] == -1]} {
    return $node
  }
  # Check if the current node is the ancestor we're looking for, and recurse upwards if it isn't  
 if {[string equal $curOperatorName $ancestorName]} {
    return $node
  } else {
    lookForAncestor [::logiscope::treeUp $node] $ancestorName
  }
}

# This procedure checks if a function is a destructor
proc isFunctionDestructor {fctNode} {
  # Get the function declarator
  set isDestructor 0
  set fctDeclarator [::logiscope::treeDown $fctNode 1]
  # Look for a child called destructor
  ::logiscope::forobj son $fctDeclarator treeChild {
    set curOperator [::logiscope::treeOperator $son]
    set curOperatorName [::logiscope::opName $curOperator]
	if {[string equal $curOperatorName destructor]} {
	  set isDestructor 1
	}
  }
  # If we reach this point, no destructor was found
  return $isDestructor
}

# This procedure looks for the class name that contains the function
proc lookForClassName {fctNode} {
  set className ""
  # First retrieve the class node
  set classNode [lookForAncestor $fctNode class]
  #Check if it is class node
  set curOperator [::logiscope::treeOperator $classNode]
  set curOperatorName [::logiscope::opName $curOperator]
  # Check if the classNode is found otherwise get from scope resolution
  if {![string equal $curOperatorName class]} {
  	 set className [getClassFromScope $fctNode]
     } else {
  	# Then get the class head
  	set classHeadNode [::logiscope::treeDown $classNode 0]
  	# Then a child called identifier
  	::logiscope::forobj son $classHeadNode treeChild {
    	set curOperator [::logiscope::treeOperator $son]
    	set curOperatorName [::logiscope::opName $curOperator]
		if {[string equal $curOperatorName identifier]} {
	  	set className [::utilities::getName $son]
		}
  	}
  
  	# If the function was not defined within a class, check if it has a scope
  	if {[string equal $className ""]} {
		set className [getClassFromScope $fctNode]
 	 }
    }
  
  return $className
}

proc getClassFromScope  {fctNode} {
  set className ""
  # Get the function declarator
  set fctDeclarator [::logiscope::treeDown $fctNode 1]
  # Look for the qualified_id child
  set fctName [::utilities::getName $fctDeclarator]
  set presentField ""
  # Get classname from qualified id
  foreach name [split $fctName '.']  {
    set className  $presentField
    set presentField $name
  }   
  return $className
}

# This procedure returns the name of the function associated to the node
proc getFunctionName {fctNode} {
  set fctName ""
  # Get the function declarator
  set fctDeclarator [::logiscope::treeDown $fctNode 1]
  # If the function has a qualified_id and scope definition, don't use the scope definition in the function name
  ::logiscope::forobj declItem $fctDeclarator treeChild {
	if {[::utilities::isTreeOperator $declItem qualified_id]} {
		set fctName [::utilities::getName [::logiscope::treeDown $declItem 1]]
	}
  } 
 # In this case, no qualified_id was found, simply return the function name
 if {[string equal $fctName ""]} {
	set fctName [::utilities::getName $fctDeclarator]   
 }
 
 return $fctName
}
