.NAME Unused variables

.DESCRIPTION
 A project shall not contain unused variables. 

.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} {
  # Initialize the variables as unused
	if {[utilities::isFirstFile]} {
		initUsedVariables
	}

	# Check all ... nodes
	utilities::filterTree $tree [list [namespace current]::check]
  
	# Look for unused variables
	if {[utilities::isLastFile]} {
		checkUnusedVariables  
	}
}

proc initUsedVariables {} {
	foreach curScope [::Scopes::getAllScopes] {
		foreach curVariable [::Semantic::getAttribute $curScope variables] {
			::Semantic::setAttribute $curVariable used 0
		}
	}
}

proc check { node } {
	# checking all nodes associated to an identifier
	switch -- [::utilities::treeOperatorName $node] {
		identifier -
		dot -
		arrow -
		qualified_id {
			# searching associated semantic object
			set semObj [::Semantic::getSemanticObject $node]
			if { $semObj != -1 } {
				# if variable, then setting it as used
				if { "[::Semantic::getAttribute $semObj kind]" == "variable"} {
					::Semantic::incrAttribute $semObj used
				}
				if { [::utilities::isTreeOperator $node dot] || [::utilities::isTreeOperator $node arrow] } {
					check [::logiscope::treeDown $node 0]
				}
				return 0
			}
		}
	}
	return 1
}

# Parse all variables of all scopes, and add violation for each unused variable (i.e declared but not used)
proc checkUnusedVariables {} {
	foreach curScope [::Scopes::getAllScopes] {
		set check 1
		if { [::Scopes::isScopeKind $curScope FUNCTION] } {
			if { [lsearch [::Semantic::getAttribute $curScope qualifier] extern] >= 0 ||
				 ![::Semantic::exists $curScope withStatements] ||
				 [::Semantic::getAttribute $curScope withStatements] == 0 } {
				 set check 0
			}
			set check 0
		}
		if { $check } {
			foreach curVar [::Semantic::getAttribute $curScope variables] {
				#puts stderr "Name [::Semantic::getAttribute $curVar name] [::Semantic::getAttribute $curVar used]"
				if {[::Semantic::hasSoftlink $curVar]} {
					continue
				}
				set classStatic 0
				if {[::Semantic::exists $curVar qualifier] &&
					[lsearch -exact [::Semantic::getAttribute $curVar qualifier] static] >= 0 &&
					[::Semantic::exists $curVar scope] &&
					[::Scopes::isScopeKind [::Semantic::getAttribute $curVar scope] CLASS]} {
					set classStatic 1
				}
				if {[::Semantic::exists $curVar used] && 
				    "[::Semantic::getAttribute $curVar name]" != "" && 
					[expr [::Semantic::getAttribute $curVar used] < 2 + $classStatic]} {
					# if current scope is FILE then look at included files
					set vio 1
					if { [::Scopes::isScopeKind $curScope FILE] } {
						set varName [::Semantic::getAttribute $curVar name]
						set includeList [::Semantic::getAttribute $curScope includes]
						foreach sc $includeList {
							set res [::Scopes::getWithName $sc variables $varName -1]
							if { $res != -1 } {
								if { [::Semantic::exists $res used] && [::Semantic::getAttribute $res used] > 1  } {
									set vio 0
								}
								break
							}
						}
					}
					if { $vio } {
						# Violation $filename $pos $end $numLine $standardName "message" 
						::Semantic::violation $curVar "MISRA_0_1_3" "MISRA_0_1_3 - Every defined variable shall be used."
					}
				}
			}
		}
	}
}
