.NAME Address of automatic storage object

.DESCRIPTION
The address of an object with automatic storage shall 
not be assigned to another object that may persist after 
the first object has ceased to exist. 

.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 compound nodes
  utilities::filterTree $tree [list [namespace current]::check]
}

proc getLevel { name levelMax } {
	variable locVar
	set level -1
	for { set lev $levelMax } { $lev >= 0 } { incr lev -1 } {
		if { [info exist locVar($lev,$name)] } {
			set level $lev
			break
		}
	}
	return $level
}

proc checkReturn { instr level } {
	set var [::logiscope::treeDown $instr 0]
	if { [::utilities::isTreeOperator $var addr] } {
		# return of an address ; is it a local object ?
		set nameNode [::logiscope::treeDown $var 0]
		if { [::utilities::isTreeOperator $nameNode identifier] } {
			set name [::utilities::getName $nameNode]
			if { [getLevel $name $level] >= 0 } {
	   	      ::logiscope::addViolation $instr
			}
		}
	}
}

proc checkAssignment { oper level } {
	# check if right term is an address
	set right [::logiscope::treeDown $oper 1]
	if { [::utilities::isTreeOperator $right addr] } {			
		# getting names of left and right part
		set left [::logiscope::treeDown $oper 0]
		if { [::utilities::isTreeOperator $left identifier] } {
			set leftName [::utilities::getName $left]					
			set right [::logiscope::treeDown $right 0]
			if { [::utilities::isTreeOperator $right identifier] } {
				set rightName [::utilities::getName $right]					
				# what is level of left and right ?
				set leftLevel [getLevel $leftName $level]
				set rightLevel [getLevel $rightName $level]
				if { $rightLevel > $leftLevel } {
		   	      ::logiscope::addViolation $oper
				}
			}
		}
	}
}

proc checkNode { level node } {
	switch -- [::utilities::treeOperatorName $node] {
		compound {
			incr level
			checkCompound $node $level
			incr level -1
			return 0
		}
		return {
			checkReturn $node $level
			return 0
		}
		ass {
			checkAssignment $node $level
			return 0
		}
	}
	return 1
}

proc checkCompound { node level } {
	variable locVar
	set stmts [::logiscope::treeDown $node 0]
	::logiscope::forobj instr $stmts treeChild {
		switch -- [::utilities::treeOperatorName $instr] {
			decl {
				set initdecls [::logiscope::treeDown $instr 1]
				::logiscope::forobj var $initdecls treeChild {
					set name [::logiscope::treeDown $var 0]
					while { [::utilities::isTreeOperator $name ptr_dcltr] } {
						set name [::logiscope::treeDown $name 1]
					}
					# current var is added in list of variables of current level
					set locVar($level,[::utilities::getName $name]) 1	
				}
			}
			compound {
				incr level
				checkCompound $instr $level
				incr level -1
			}
			default {
				utilities::filterTree $instr [list [namespace current]::checkNode $level]
			}
		}
	}
}

proc check { node } {
	variable locVar
	if { [::utilities::isTreeOperator $node compound] } {
		if { [info exist locVar] } {
			array unset locVar
		}
		checkCompound $node 0
		return 0
	}
	return 1
}
