.NAME Instanciation of templates

.DESCRIPTION
	All class templates, function templates, class template 
member functions and class template static members 
shall be instantiated at least once. 

.COMMENT V7.0

.SEVERITY Required

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

.REQUIRED cpp_semantic

.COMMAND tcl

.CODE

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

proc compute {standardName tree} {
	if {[string equal [::logiscope::fileName] [::logiscope::firstFile]]} {
		initTemplateObjects
		checkTemplateInstanciations
		checkTypeDefs
	}

	# Check all ... nodes
	utilities::filterTree $tree [list [namespace current]::check]
  
	if {[string equal [::logiscope::fileName] [::logiscope::lastFile]]} {
		# Look for unused functions
		checkTemplateObjects
	}
}

proc initTemplateObjects {} {
	foreach curScope [::Scopes::getAllScopes TEMPLATE] {
		markTemplateObjects $curScope
	}
}

proc markTemplateObjects {scope} {
	if {[string equal [::Semantic::getAttribute $scope scopeKind] "CLASS"]} {
		::Semantic::setAttribute $scope used 0
	}
	
	foreach function [::Semantic::getAttribute $scope functions] {
		::Semantic::setAttribute $function used 0
	}
	foreach subScope [::Semantic::getAttribute $scope sub] {
		markTemplateObjects $subScope
	}
}

proc checkTemplateInstanciations {} {
	foreach curScope [::Scopes::getAllScopes] {
		foreach curVar [::Semantic::getAttribute $curScope variables] {
			set varType [::Semantic::getAttribute $curVar type]
			set typeKind [::Semantic::getAttribute $varType typeKind]
			if {[string equal $typeKind "TypeInstanciated"]} {
				checkInstanciatedType $varType
			}
		}
	}
}

proc checkTypeDefs {} {
	foreach curTypeDef [::Types::getAllTypes Typedef] {
		set typeKind [::Semantic::getAttribute [::Semantic::getAttribute $curTypeDef type] typeKind]
		if {[string equal $typeKind "TypeInstanciated"]} {
			checkInstanciatedType [::Semantic::getAttribute $curTypeDef type]			
		}
	}
}

proc checkInstanciatedType {instanciatedType} {
	set templateType [::Semantic::getAttribute $instanciatedType type]
	set templateClass [::Semantic::getAttribute $templateType scopeClass]
	::Semantic::setAttribute $templateClass used 1
	set className [::Semantic::getAttribute $templateClass name]
	foreach tplFunc [::Semantic::getAttribute $templateClass functions]] {
		set funcName [::Semantic::getAttribute $tplFunc name]
		if {[string equal [string range $funcName 0 0 ] "~"]} {
			set funcName [string range $funcName 1 end]
		}
		if {[string equal $className $funcName]} {
			::Semantic::setAttribute $tplFunc used 1
		}
	}
}

proc checkTemplateObjects {} {
	foreach curScope [::Scopes::getAllScopes TEMPLATE] {
		testTemplateObjects $curScope
	}
}

proc testTemplateObjects {scope} {
	if {[string equal [::Semantic::getAttribute $scope scopeKind] "CLASS"]} {
		if {[expr [::Semantic::getAttribute $scope used] == 0]} {
			::Semantic::violation $scope "MISRA_Rule14_7_1" "MISRA_Rule14_7_1 - All class templates, function templates, class template member functions and class template static members shall be instantiated at least once."
		}
	}

	foreach function [::Semantic::getAttribute $scope functions] {
		if {[expr [::Semantic::getAttribute $function used] == 0]} {
			::Semantic::violation $function "MISRA_Rule14_7_1" "MISRA_Rule14_7_1 - All class templates, function templates, class template member functions and class template static members shall be instantiated at least once."
		}
	}
	foreach subScope [::Semantic::getAttribute $scope sub] {
		testTemplateObjects $subScope
	}
}
		
proc check { node } {
	if {[::utilities::isTreeOperator $node call]} {
		set function [::Semantic::getCalledFunction $node]
		if {$function != -1} {
			if {[::Semantic::exists $function name]} {
				set funcName [::Semantic::getAttribute $function name] 
				::Semantic::setAttribute $function used 1
			}
		}
	}
	return 1
}
