.NAME Constructors

.DESCRIPTION
All constructors that are callable with a single 
argument of fundamental type shall be declared explicit. 

.COMMENT V7.0

.SEVERITY Required

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

.PARAMETERS LIST "int32_t" END LIST 

.COMMAND tcl

.CODE

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

variable fundamentalTypes
set fundamentalTypes { char "unsigned char" "signed char" 
	bool 
	short "short int" "signed short" "unsigned short" 
	int "signed int" "unsigned int" 
	__int8 __int16 __int32 __int64 
	long "signed long" "unsigned long" 
	"long long" "signed long long" "unsigned long long"
	float double "long double" __wchar_t }

proc compute {standardName tree} {
  variable fundamentalTypes
  variable CurrentParameterList
  foreach ft [lindex $CurrentParameterList 0] {
	lappend fundamentalTypes $ft
  }
  # Check all class nodes
  utilities::filterTree $tree [list [namespace current]::check]
}

proc checkIfConstructor { name func_dcltr declaration_specifiers } {
	variable fundamentalTypes
	# check if explicit
	set explicit 0
	::logiscope::forobj st $declaration_specifiers treeChild {
		if { [::utilities::isTreeOperator $st storage_class] } {
			set kind [::utilities::treeAtomString $st]
			if { "$kind" == "explicit" } {
				set explicit 1
			}
		}
	}
	if { $explicit == 0 } {
		if { [::utilities::isTreeOperator $func_dcltr func_dcltr] } {
			set nameNode [::logiscope::treeDown $func_dcltr 0]
			if { "[::utilities::getName $nameNode]" == "$name" } {
				# this is a constructor
				# how many parameters ?
				set parmlist [::logiscope::treeDown $func_dcltr 1]
				if { [::logiscope::treeLength $parmlist] == 1 } {
					# only one parameter
					# is the type of this paramater a fundamental type ?
					set parm_decl [::logiscope::treeDown $parmlist 0]
					set ds [::logiscope::treeDown $parm_decl 0]
					set ident [::logiscope::treeDown $ds 0]
					set typeName [::utilities::getName $ident]					
					if { [lsearch $fundamentalTypes $typeName] >= 0 } {
						::logiscope::addViolation $func_dcltr
					}
				}
			}
		}
	}
}

proc checkClass { node } {
	# get name of class
	set class_head [::logiscope::treeDown $node 0]
	set name [::utilities::getName [::logiscope::treeDown $class_head 1]]
	# looking for constructors
	set class_decls [::logiscope::treeDown $node 1]
	::logiscope::forobj cds $class_decls treeChild {
		set accessNode [::logiscope::treeDown $cds 0]
		set access [::utilities::treeAtomString $accessNode]
		if { "$access" == "public" } {
			set cdl [::logiscope::treeDown $cds 1]
			::logiscope::forobj member $cdl treeChild {
				switch -- [::utilities::treeOperatorName $member] {
					fndef {
						set declspec [::logiscope::treeDown $member 0]
						checkIfConstructor $name [::logiscope::treeDown $member 1] $declspec
					}
					member_decl {
						set declspec [::logiscope::treeDown $member 0]
						set initdecls [::logiscope::treeDown $member 1]
						if { [::utilities::isTreeOperator $initdecls initdecls] } {
							set dcltr_noinit [::logiscope::treeDown $initdecls 0]
							if { [::utilities::isTreeOperator $dcltr_noinit dcltr_noinit] } {
								set func_dcltr [::logiscope::treeDown $dcltr_noinit 0]
								checkIfConstructor $name $func_dcltr $declspec
							}
						}
					}
				}
			}
		}
	}
}

proc check { node } {
	if	{ [::utilities::isTreeOperator $node class] } {
		checkClass $node
		return 0
	}
	return 1
}
