.NAME Private member data

.DESCRIPTION
 Member data in non-POD class types shall be private. 

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

proc isDestructor {dcltr} {
	set return 0
	if {$dcltr eq "NULL"} {
		return 0
	}
	#puts stderr "[string repeat " " [info level]]isDestructor $dcltr [::utilities::treeOperatorName $dcltr]"
	if { [::utilities::isTreeOperator $dcltr destructor] } {
		#puts stderr "[string repeat " " [info level]]<- 1 isDestructor [::utilities::treeOperatorName $dcltr]"
		return 1
	}
	if { [::logiscope::treeLength $dcltr] } {
		::logiscope::forobj child $dcltr treeChild {
			if { [isDestructor $child] } {
				set return 1
				break
			}
		}
	}
	#puts stderr "[string repeat " " [info level]]<- $return isDestructor [::utilities::treeOperatorName $dcltr]"
	return $return
}

proc isPOD {class_decls} {
	#puts stderr "isPOD $class_decls"
	set return 1
	::logiscope::forobj class_decls_section $class_decls treeChild {
		set component_decl_list [::logiscope::treeDown $class_decls_section 1]
		::logiscope::forobj member $component_decl_list treeChild {
			if { [::utilities::isTreeOperator $member member_decl] } {
				set declaration_specifiers [::logiscope::treeDown $member 0]
				set checkFurther 1
				::logiscope::forobj decl $declaration_specifiers treeChild {
					if { [::utilities::isTreeOperator $decl storage_class] } {
						if { "[::utilities::treeAtomString $decl]" == "virtual" } {
							# not POD
							set return 0
							break
						}
						if { "[::utilities::treeAtomString $decl]" == "static" } {
							# static member: no need to check this member further.
							set checkFurther 0
							break
						}
					} elseif { [::utilities::isTreeOperator $decl type_qualifier] } {
						if { "[::utilities::treeAtomString $decl]" == "const" } {
							# const member: no need to check this member further.
							set checkFurther 0
							break
						}
					}
				}
				if { !$return } {
					break
				}
				if { !$checkFurther } {
					continue
				}
				# member without virtuel nor static nor const
				set initdecls [::logiscope::treeDown $member 1]
				set dc [::logiscope::treeDown $initdecls 0]
				if { [isDestructor $dc] } {
					set return 0
					break
				}
			}
		}
		if { !$return } {
			break
		}
	}
	return $return
}

proc check { node } {
	if { [::utilities::isTreeOperator $node class_decls_section] } {
		# checking if this is a class
		set father [::logiscope::treeUp $node]
		set class [::logiscope::treeUp $father]
		if { [::utilities::isTreeOperator $class class ] } {
			set class_head [::logiscope::treeDown $class 0]
			set kind [::logiscope::treeDown $class_head 0]
			if  { [::utilities::isTreeOperator $kind class_kw] } {
				# We have a class. Check if it is a POD
				if {![isPOD $father]} {
				# checking if access is private
				set access_specifier [::logiscope::treeDown $node 0]
				if { ![::utilities::isTreeOperator $access_specifier access_specifier] || "[::utilities::treeAtomString $access_specifier]" != "private" } {
					# Not in private part, attributes forbidden
					set component_decl_list [::logiscope::treeDown $node 1]
					::logiscope::forobj member $component_decl_list treeChild {
						if { [::utilities::isTreeOperator $member member_decl] } {
							# checking if this is an attribute
							set initdecls [::logiscope::treeDown $member 1]
							set dc [::logiscope::treeDown $initdecls 0]
							set okAtt 1
							if { [::utilities::isTreeOperator $dc dcltr_noinit] } {
								set fd [::logiscope::treeDown $dc 0]
								while { [::utilities::isTreeOperator $fd ptr_dcltr] } {
									set fd [::logiscope::treeDown $fd 1]
								}
								if { [::utilities::isTreeOperator $fd func_dcltr] } {
									set okAtt 0
								}
							}
							if { $okAtt } {
								# is it an attribute or a constant ?
								set declaration_specifiers [::logiscope::treeDown $member 0]
								set isConst 0
								set isVirtual 0
								set isTypedef 0
								::logiscope::forobj decl $declaration_specifiers treeChild {
									if { [::utilities::isTreeOperator $decl type_qualifier] &&
										 "[::utilities::treeAtomString $decl]" == "const" } {
										set isConst 1
										break
									} elseif { [::utilities::isTreeOperator $decl storage_class] &&
										 "[::utilities::treeAtomString $decl]" == "virtual" } {
										set isVirtual 1
										break
									} elseif { [::utilities::isTreeOperator $decl storage_class] &&
										 "[::utilities::treeAtomString $decl]" == "typedef" } {
										set isTypedef 1
										break
									}
								}
								if { !$isConst && !$isVirtual && !$isTypedef } {
	#								set initdecls [::logiscope::treeDown $member 1]
									::logiscope::forobj var $initdecls treeChild {
										::logiscope::addViolation $var
									}
								}
							}
						}
					}
				}
				}
			}
		}
	}
	return 1
}
