.NAME Variables defined before use

.DESCRIPTION
All variables shall have a defined value before they are used.

.COMMENT V7.0

.SEVERITY Required

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

.COMMAND tcl

.REQUIRED cpp_semantic

.CODE

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

proc compute {standardName tree} {
  # Check all class nodes
  variable stdn
  set stdn $standardName
  variable seen
  utilities::filterTree $tree [list [namespace current]::check]
  if { [array exists seen] } {
	array unset seen
  }

}

proc check { node } {
	variable seen
	variable stdn
	switch -- [::utilities::treeOperatorName $node] {
		fndef {
			# found a function
			set func_dcltr [::logiscope::treeDown $node 1]
			set funcNameNode [::logiscope::treeDown $func_dcltr 0]
			set semObj [::Semantic::getSemanticObject $funcNameNode]
			if { $semObj != -1 } {
				if { [::Semantic::isKind $semObj scope] } {
					if { [::Scopes::isScopeKind $semObj FUNCTION] } {
						# we have found the semantic scope of the function
						set upScope [::Semantic::getAttribute $semObj super]
						if { [::Scopes::isScopeKind $upScope CLASS] } {
							# this is a method
							set className [::Semantic::getAttribute $upScope name]
							set funcName [::Semantic::getAttribute $semObj name]
							if { "$className" == "$funcName" } {
								# this is a constructor
								# building list of non static attributes of the class
								set attributes [::Semantic::getAttribute $upScope variables]
								if { [llength $attributes] > 0 } {
									if { [array exists seen] } {
										array unset seen
									}
									foreach att $attributes {
										if { [lsearch [::Semantic::getAttribute $att qualifier] static] >= 0 } {
											set seen($att) 1
										}
										if { "[::Semantic::getAttribute $att defaultValue]" != "" } {
											set seen($att) 1
										}
									}
									# checking body of method
									set ctor_initializer [::logiscope::treeDown $node 3]
									utilities::filterTree $ctor_initializer [list [namespace current]::checkCompound]
									foreach att $attributes {
										if { [info exists seen($att)] } {
											if { $seen($att) != 1 } {
												::Semantic::violation $semObj $stdn "Attribute [::Semantic::getAttribute $att name] used before set"
											}
										} else {
											::Semantic::violation $semObj $stdn "Attribute [::Semantic::getAttribute $att name] not set"
										}
									}
								}
							}
						}						
					}
				}
			}
		}
		stmts {
			checkLocVar "" $node
			return 0
		}
	}
	return 1
}

proc setVar { node tem } {
	variable seen
	set semObj [::Semantic::getSemanticObject $node]
	if { $semObj != -1 } {
		if { [::Semantic::isKind $semObj variable] } {
			if { ![info exists seen($semObj)] } {
				set seen($semObj) $tem
			}
		}
	}
}

proc checkCompound { node } {
	switch -- [::utilities::treeOperatorName $node] {
		member_init {
			set identNode [::logiscope::treeDown $node 0]
			setVar $identNode 1
			return 0
		}
		ass {
			set leftNode [::logiscope::treeDown $node 0]
			setVar $leftNode 1
		}
		identifier -
		dot -
		arrow {
			setVar $node -1
		}
	}
	return 1
}

proc checkLocVar { curScope node } {
#puts "checkLocVar $curScope [::utilities::treeOperatorName $node]"
	variable seen
	variable stdn
	switch -- [::utilities::treeOperatorName $node] {
		stmts {
			set scope [::Scopes::searchScope $node]
			if { $scope != -1 && [::Scopes::isScopeKind $scope LOCAL] } {
				set variables [::Semantic::getAttribute $scope variables]
				if { [llength $variables] > 0 } {
					foreach att $variables {
						if { [lsearch [::Semantic::getAttribute $att qualifier] static] >= 0 } {
							set seen($att) 1
							continue
						}
						if { "[::Semantic::getAttribute $att defaultValue]" != "" } {
							set seen($att) 1
							continue
						}
						set typ [::Types::getRealType [::Semantic::getAttribute $att type]]
						if { $typ != -1 } {
							set tk [::Semantic::getAttribute $typ typeKind]
							if { "$tk" == "TypeClass" || "$tk" == "TypeUnknown" } {
								set seen($att) 1
							} 
						} else {
							set seen($att) 1
						}
					}
					# checking compounds
					::logiscope::forobj stmt $node treeChild {
						utilities::filterTree $stmt [list [namespace current]::checkLocVar $scope]
					}
					foreach att $variables {
						if { [info exists seen($att)] } {
							if { $seen($att) != 1 } {
								::Semantic::violation $att $stdn "Variable [::Semantic::getAttribute $att name] used before set"
							}
						}
					}
				}
			}
			return 0
		}
		decl {
			# declaration not checked
			return 0
		}
		ass {
			set leftNode [::logiscope::treeDown $node 0]
			setVar $leftNode 1
		}
		identifier -
		dot -
		arrow {
			setVar $node -1
		}		
	}
	return 1
}

