nitmetrics: set private visibility to internal services
[nit.git] / src / metrics / inheritance_metrics.nit
index 99408d4..0cfef0b 100644 (file)
@@ -21,87 +21,57 @@ import model
 private import metrics_base
 
 redef class Model
-
-       # List of modules in std lib
-       # FIXME this is quite ugly, find a dynamic way...
-       fun std_modules: Set[String] do
-               if self.std_modules_cache == null then
-                       self.std_modules_cache = new HashSet[String]
-                       self.std_modules_cache.add("collection")
-                       self.std_modules_cache.add("abstract_collection")
-                       self.std_modules_cache.add("array")
-                       self.std_modules_cache.add("hash_collection")
-                       self.std_modules_cache.add("list")
-                       self.std_modules_cache.add("range")
-                       self.std_modules_cache.add("sorter")
-                       self.std_modules_cache.add("environ")
-                       self.std_modules_cache.add("exec")
-                       self.std_modules_cache.add("file")
-                       self.std_modules_cache.add("gc")
-                       self.std_modules_cache.add("hash")
-                       self.std_modules_cache.add("kernel")
-                       self.std_modules_cache.add("math")
-                       self.std_modules_cache.add("standard")
-                       self.std_modules_cache.add("stream")
-                       self.std_modules_cache.add("string")
-                       self.std_modules_cache.add("string_search")
-                       self.std_modules_cache.add("time")
-               end
-               return self.std_modules_cache.as(not null)
-       end
-       private var std_modules_cache: nullable Set[String]
-
        # Extract the subset of classes from a set of mclass
-       fun extract_classes(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_classes(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if mclass.is_class then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of interfaces from a set of mclass
-       fun extract_interfaces(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_interfaces(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if mclass.is_interface then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of generic classes/interfaces from a set of mclass
-       fun extract_generics(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_generics(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if mclass.arity > 0 then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of abstract classes from a set of mclass
-       fun extract_abstracts(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_abstracts(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if mclass.is_abstract then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of user defined classes/interfaces from a set of mclass
-       fun extract_user_defined(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_user_defined(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if mclass.is_user_defined then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of user defined modules from a set of mmodules
-       fun extract_user_defined_modules(mmodules: Collection[MModule]): Set[MModule] do
+       private fun extract_user_defined_modules(mmodules: Collection[MModule]): Set[MModule] do
                var lst = new HashSet[MModule]
                for mmodule in mmodules do if mmodule.is_user_defined then lst.add(mmodule)
                return lst
        end
 
        # Extract the subset of classes/interfaces from sl lib
-       fun extract_stdlib(mclasses: Collection[MClass]): Set[MClass] do
+       private fun extract_stdlib(mclasses: Collection[MClass]): Set[MClass] do
                var lst = new HashSet[MClass]
                for mclass in mclasses do if not mclass.is_user_defined then lst.add(mclass)
                return lst
        end
 
        # Extract the subset of user defined modules from std lib
-       fun extract_stdlib_modules(mmodules: Collection[MModule]): Set[MModule] do
+       private fun extract_stdlib_modules(mmodules: Collection[MModule]): Set[MModule] do
                var lst = new HashSet[MModule]
                for mmodule in mmodules do if not mmodule.is_user_defined then lst.add(mmodule)
                return lst
@@ -151,9 +121,9 @@ redef class MClass
                self.noa = ancestors.length
                self.noac = model.extract_classes(ancestors).length
                self.noai = model.extract_interfaces(ancestors).length
-               self.noc = children(model).length
-               self.nocc = model.extract_classes(children(model)).length
-               self.noci = model.extract_interfaces(children(model)).length
+               self.noc = children.length
+               self.nocc = model.extract_classes(children).length
+               self.noci = model.extract_interfaces(children).length
                self.nod = descendants.length
                self.nodc = model.extract_classes(descendants).length
                self.nodi = model.extract_interfaces(descendants).length
@@ -168,9 +138,9 @@ redef class MClass
                self.noaud = model.extract_user_defined(ancestors).length
                self.noacud = model.extract_user_defined(model.extract_classes(ancestors)).length
                self.noaiud = model.extract_user_defined(model.extract_interfaces(ancestors)).length
-               self.nocud = model.extract_user_defined(children(model)).length
-               self.noccud = model.extract_user_defined(model.extract_classes(children(model))).length
-               self.nociud = model.extract_user_defined(model.extract_interfaces(children(model))).length
+               self.nocud = model.extract_user_defined(children).length
+               self.noccud = model.extract_user_defined(model.extract_classes(children)).length
+               self.nociud = model.extract_user_defined(model.extract_interfaces(children)).length
                self.nodud = model.extract_user_defined(descendants).length
                self.nodcud = model.extract_user_defined(model.extract_classes(descendants)).length
                self.nodiud = model.extract_user_defined(model.extract_interfaces(descendants)).length
@@ -179,72 +149,8 @@ redef class MClass
                self.ditiud = ud_interface_path_to_object.length
        end
 
-       fun is_class: Bool do
-               return self.kind == concrete_kind or self.kind == abstract_kind
-       end
-
-       fun is_interface: Bool do
-               return self.kind == interface_kind
-       end
-
-       fun is_abstract: Bool do
-               return self.kind == abstract_kind
-       end
-
-       fun is_user_defined: Bool do
-               return self.intro_mmodule.is_user_defined
-       end
-
-       # Get parents of the class (direct super classes only)
-       fun parents: Set[MClass] do
-               var lst = new HashSet[MClass]
-               # explore all definitions of the class (refinement)
-               for mclassdef in self.mclassdefs do
-                       for parent in mclassdef.supertypes do
-                               lst.add(parent.mclass)
-                       end
-               end
-               return lst
-       end
-
-       # Get ancestors of the class (all super classes)
-       fun ancestors: Set[MClass] do
-               var lst = new HashSet[MClass]
-               for mclassdef in self.mclassdefs do
-                       for super_mclassdef in mclassdef.in_hierarchy.greaters do
-                               if super_mclassdef == mclassdef then continue  # skip self
-                               lst.add(super_mclassdef.mclass)
-                       end
-               end
-               return lst
-       end
-
-       # Get children of the class (direct subclasses only)
-       fun children(model: Model): Set[MClass] do
-               var lst = new HashSet[MClass]
-               for other in model.mclasses do
-                       if other == self then continue # skip self
-                       if other.parents.has(self) then
-                               lst.add(other)
-                       end
-               end
-               return lst
-       end
-
-       # Get children of the class (direct subclasses only)
-       fun descendants: Set[MClass] do
-               var lst = new HashSet[MClass]
-               for mclassdef in self.mclassdefs do
-                       for sub_mclassdef in mclassdef.in_hierarchy.smallers do
-                               if sub_mclassdef == mclassdef then continue  # skip self
-                               lst.add(sub_mclassdef.mclass)
-                       end
-               end
-               return lst
-       end
-
        # Return the longest path from class to root hierarchy
-       fun path_to_object: Array[MClass] do
+       private fun path_to_object: Array[MClass] do
                var path = new Array[MClass]
                var max_dit: nullable Int = null
                var max_parent: nullable MClass = null
@@ -268,7 +174,7 @@ redef class MClass
        end
 
        # Return the longest path from class to root hierarchy
-       fun ud_path_to_object: Array[MClass] do
+       private fun ud_path_to_object: Array[MClass] do
                var path = new Array[MClass]
                if not self.is_user_defined then return path
                var max_dit: nullable Int = null
@@ -293,7 +199,7 @@ redef class MClass
        end
 
        # Return the longest path from class to root hierarchy following only classes relations
-       fun class_path_to_object: Array[MClass] do
+       private fun class_path_to_object: Array[MClass] do
                var path = new Array[MClass]
                if not self.is_class then return path
                var max_dit: nullable Int = null
@@ -318,7 +224,7 @@ redef class MClass
        end
 
        # Return the longest path from class to root hierarchy following only interfaces relations
-       fun interface_path_to_object: Array[MClass] do
+       private fun interface_path_to_object: Array[MClass] do
                var path = new Array[MClass]
                if not self.is_interface then return path
                var max_dit: nullable Int = null
@@ -343,7 +249,7 @@ redef class MClass
        end
 
        # Return the longest path from class to root hierarchy following only ud classes relations
-       fun ud_class_path_to_object: Array[MClass] do
+       private fun ud_class_path_to_object: Array[MClass] do
                var path = new Array[MClass]
                if not self.is_class or not self.is_user_defined then return path
                var max_dit: nullable Int = null
@@ -368,7 +274,7 @@ redef class MClass
        end
 
        # Return the longest path from class to root hierarchy following only ud interfaces relations
-       fun ud_interface_path_to_object: Array[MClass] do
+       private fun ud_interface_path_to_object: Array[MClass] do
                var path = new Array[MClass]
                if not self.is_interface or not self.is_user_defined then return path
                var max_dit: nullable Int = null
@@ -394,210 +300,210 @@ redef class MClass
 
        # * -> * DUI
 
-       fun is_dui_eligible: Bool do
+       private fun is_dui_eligible: Bool do
                for parent in parents do if parent.name != "Object" then return true
                return false
        end
-       fun is_ccdui_eligible: Bool do
+       private fun is_ccdui_eligible: Bool do
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_class then return true
                return false
        end
-       fun is_cidui_eligible: Bool do
+       private fun is_cidui_eligible: Bool do
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_iidui_eligible: Bool do
+       private fun is_iidui_eligible: Bool do
                if not is_interface then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_if_eligible(model: Model): Bool do return not children(model).is_empty
-       fun is_ccif_eligible(model: Model): Bool do
+       private fun is_if_eligible(model: Model): Bool do return not children.is_empty
+       private fun is_ccif_eligible(model: Model): Bool do
                if not is_class then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_icif_eligible(model: Model): Bool do
+       private fun is_icif_eligible(model: Model): Bool do
                if not is_interface then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_iiif_eligible(model: Model): Bool do
+       private fun is_iiif_eligible(model: Model): Bool do
                if not is_interface then return false
-               for child in children(model) do if child.is_interface then return true
+               for child in children do if child.is_interface then return true
                return false
        end
 
        # SL -> * DUI
 
-       fun is_sldui_eligible: Bool do
+       private fun is_sldui_eligible: Bool do
                if is_user_defined then return false
                for parent in parents do if parent.name != "Object" then return true
                return false
        end
-       fun is_slccdui_eligible: Bool do
+       private fun is_slccdui_eligible: Bool do
                if is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_class then return true
                return false
        end
-       fun is_slcidui_eligible: Bool do
+       private fun is_slcidui_eligible: Bool do
                if is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_sliidui_eligible: Bool do
+       private fun is_sliidui_eligible: Bool do
                if is_user_defined then return false
                if not is_interface then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_slif_eligible(model: Model): Bool do
+       private fun is_slif_eligible(model: Model): Bool do
                if is_user_defined then return false
-               return not children(model).is_empty
+               return not children.is_empty
        end
-       fun is_slccif_eligible(model: Model): Bool do
+       private fun is_slccif_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_class then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_slicif_eligible(model: Model): Bool do
+       private fun is_slicif_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_sliiif_eligible(model: Model): Bool do
+       private fun is_sliiif_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_interface then return true
+               for child in children do if child.is_interface then return true
                return false
        end
 
        # SL -> SL
 
-       fun is_slifsl_eligible(model: Model): Bool do
+       private fun is_slifsl_eligible(model: Model): Bool do
                if is_user_defined then return false
-               for child in children(model) do if not child.is_user_defined then return true
+               for child in children do if not child.is_user_defined then return true
                return false
        end
-       fun is_slccifsl_eligible(model: Model): Bool do
+       private fun is_slccifsl_eligible(model: Model): Bool do
                if is_user_defined then return false
                if is_class then return false
-               for child in children(model) do if not child.is_user_defined and child.is_class then return true
+               for child in children do if not child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_slicifsl_eligible(model: Model): Bool do
+       private fun is_slicifsl_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if not child.is_user_defined and child.is_class then return true
+               for child in children do if not child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_sliiifsl_eligible(model: Model): Bool do
+       private fun is_sliiifsl_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if not child.is_user_defined and child.is_interface then return true
+               for child in children do if not child.is_user_defined and child.is_interface then return true
                return false
        end
 
        # SL -> UD
 
-       fun is_slifud_eligible(model: Model): Bool do
+       private fun is_slifud_eligible(model: Model): Bool do
                if is_user_defined then return false
-               for child in children(model) do if child.is_user_defined then return true
+               for child in children do if child.is_user_defined then return true
                return false
        end
-       fun is_slccifud_eligible(model: Model): Bool do
+       private fun is_slccifud_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_class then return false
-               for child in children(model) do if child.is_user_defined and child.is_class then return true
+               for child in children do if child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_slicifud_eligible(model: Model): Bool do
+       private fun is_slicifud_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_user_defined and child.is_class then return true
+               for child in children do if child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_sliiifud_eligible(model: Model): Bool do
+       private fun is_sliiifud_eligible(model: Model): Bool do
                if is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_user_defined and child.is_interface then return true
+               for child in children do if child.is_user_defined and child.is_interface then return true
                return false
        end
 
        # UD -> *
 
-       fun is_uddui_eligible: Bool do
+       private fun is_uddui_eligible: Bool do
                if not is_user_defined then return false
                for parent in parents do if parent.name != "Object" then return true
                return false
        end
-       fun is_udccdui_eligible: Bool do
+       private fun is_udccdui_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_class then return true
                return false
        end
-       fun is_udcidui_eligible: Bool do
+       private fun is_udcidui_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_udiidui_eligible: Bool do
+       private fun is_udiidui_eligible: Bool do
                if not is_user_defined then return false
                if not is_interface then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_udif_eligible(model: Model): Bool do
+       private fun is_udif_eligible(model: Model): Bool do
                if not is_user_defined then return false
-               return not children(model).is_empty
+               return not children.is_empty
        end
-       fun is_udccif_eligible(model: Model): Bool do
+       private fun is_udccif_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_class then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_udicif_eligible(model: Model): Bool do
+       private fun is_udicif_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_class then return true
+               for child in children do if child.is_class then return true
                return false
        end
-       fun is_udiiif_eligible(model: Model): Bool do
+       private fun is_udiiif_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_interface then return true
+               for child in children do if child.is_interface then return true
                return false
        end
 
        # UD -> SL
 
-       fun is_udduisl_eligible: Bool do
+       private fun is_udduisl_eligible: Bool do
                if not is_user_defined then return false
                for parent in parents do if not parent.is_user_defined and parent.name != "Object" then return true
                return false
        end
-       fun is_udccduisl_eligible: Bool do
+       private fun is_udccduisl_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_class then return true
                return false
        end
-       fun is_udciduisl_eligible: Bool do
+       private fun is_udciduisl_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_interface then return true
                return false
        end
-       fun is_udiiduisl_eligible: Bool do
+       private fun is_udiiduisl_eligible: Bool do
                if not is_user_defined then return false
                if not is_interface then return false
                for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_interface then return true
@@ -606,52 +512,51 @@ redef class MClass
 
        # UD -> UD
 
-       fun is_udduiud_eligible: Bool do
+       private fun is_udduiud_eligible: Bool do
                if not is_user_defined then return false
                for parent in parents do if parent.name != "Object" and parent.is_user_defined then return true
                return false
        end
-       fun is_udccduiud_eligible: Bool do
+       private fun is_udccduiud_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_class and parent.is_user_defined then return true
                return false
        end
-       fun is_udciduiud_eligible: Bool do
+       private fun is_udciduiud_eligible: Bool do
                if not is_user_defined then return false
                if not is_class then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface and parent.is_user_defined then return true
                return false
        end
-       fun is_udiiduiud_eligible: Bool do
+       private fun is_udiiduiud_eligible: Bool do
                if not is_user_defined then return false
                if not is_interface then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface and parent.is_user_defined then return true
                return false
        end
-       fun is_udifud_eligible(model: Model): Bool do
+       private fun is_udifud_eligible(model: Model): Bool do
                if not is_user_defined then return false
-               return not children(model).is_empty
+               return not children.is_empty
        end
-       fun is_udccifud_eligible(model: Model): Bool do
+       private fun is_udccifud_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_class then return false
-               for child in children(model) do if child.is_user_defined and child.is_class then return true
+               for child in children do if child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_udicifud_eligible(model: Model): Bool do
+       private fun is_udicifud_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_user_defined and child.is_class then return true
+               for child in children do if child.is_user_defined and child.is_class then return true
                return false
        end
-       fun is_udiiifud_eligible(model: Model): Bool do
+       private fun is_udiiifud_eligible(model: Model): Bool do
                if not is_user_defined then return false
                if not is_interface then return false
-               for child in children(model) do if child.is_user_defined and child.is_interface then return true
+               for child in children do if child.is_user_defined and child.is_interface then return true
                return false
        end
-
 end
 
 redef class MModule
@@ -660,8 +565,8 @@ redef class MModule
        private var nc: Int = 0                 # (NC)  Number of Classes
        private var ni: Int = 0                 # (NI)  Number of Interfaces
        private var nac : Int = 0               # (NAC) Number of Abstract Classes
-       protected var ngc : Int = 0             # (NGC) Number of Generic Classes
-       protected var ngi : Int = 0             # (NGI) Number of Generic Interfaces
+       private var ngc : Int = 0               # (NGC) Number of Generic Classes
+       private var ngi : Int = 0               # (NGI) Number of Generic Interfaces
 
        private var dit = ""                    # (DIT) Global Depth in Inheritance Tree
        private var dui = ""                    # (DUI) Proportion of types that either implement an interface or extend another type other than Object
@@ -673,7 +578,7 @@ redef class MModule
        private var icif = ""                   # (ICIF) Proportion of interfaces implemented by some other class.
        private var iiif = ""                   # (IIIF) Proportion of interfaces extended by some other interface.
 
-       fun compute_module_inheritance_metrics(model: Model) do
+       private fun compute_module_inheritance_metrics(model: Model) do
                var ditsum = 0
                var dui_count = 0
                var ccdui_count = 0
@@ -683,15 +588,15 @@ redef class MModule
                var ccif_count = 0
                var icif_count = 0
                var iiif_count = 0
-
+               var count = 0
                for mmodule in self.in_nesting.greaters do
                        for mclass in mmodule.intro_mclasses do
+                               count += 1
                                if mclass.is_class then nc += 1
                                if mclass.is_class and mclass.arity > 0 then ngc += 1
                                if mclass.is_class and mclass.is_abstract then nac += 1
                                if mclass.is_interface then ni += 1
                                if mclass.is_interface and mclass.arity > 0 then ngi += 1
-
                                ditsum += mclass.path_to_object.length
                                if mclass.is_dui_eligible then dui_count += 1
                                if mclass.is_ccdui_eligible then ccdui_count += 1
@@ -705,20 +610,16 @@ redef class MModule
                end
 
                self.nm = self.in_nesting.greaters.length
-               dit = div(ditsum, nc + ni)
-               dui = div(dui_count * 100, nc + ni)
+               dit = div(ditsum, count)
+               dui = div(dui_count * 100, count)
                ccdui = div(ccdui_count * 100, nc)
                cidui = div(cidui_count * 100, nc)
                iidui = div(iidui_count * 100, ni)
-               inhf = div(if_count * 100, nc + ni)
+               inhf = div(if_count * 100, count)
                ccif = div(ccif_count * 100, nc)
                icif = div(icif_count * 100, ni)
                iiif = div(iiif_count * 100, ni)
        end
-
-       fun is_user_defined: Bool do
-               return not self.model.std_modules.has(self.name)
-       end
 end
 
 # Print inheritance usage metrics
@@ -796,6 +697,7 @@ do
        var udiiduisl = ""                      # (UDIIDUISL) Proportion of user-defined interfaces that extend some other SL interface.
 
        # (UD -> UD) User-defined summary inheritance metrics
+       var ditud = ""
        var udduiud = ""                        # (UDDUIUD) Proportion user-defined of types that either implement an interface or extend another type user-defined
        var udccduiud = ""                      # (UDCCDUIUD) Proportion of user-defined classes that extend some other user-defined class.
        var udciduiud = ""                      # (UDCIDUIUD) Proportion of user-defined classes that implement some other user-defined interface.
@@ -843,6 +745,8 @@ do
 
        # * -> *
        var ditsum = 0
+       var ditudsum = 0
+
        var dui_count = 0
        var ccdui_count = 0
        var cidui_count = 0
@@ -902,6 +806,7 @@ do
 
        for mclass in model.mclasses do
                ditsum += mclass.dit
+               ditudsum += mclass.ditud
 
                # * -> *
                if mclass.is_dui_eligible then dui_count += 1
@@ -964,7 +869,8 @@ do
 
        # * -> *
        dit = div(ditsum, model.mclasses.length)
-       dui = div(dui_count * 100, nc + ni)
+       ditud = div(ditudsum, ncud + niud)
+       dui = div(dui_count * 100, model.mclasses.length)
        ccdui = div(ccdui_count * 100, nc)
        cidui = div(cidui_count * 100, nc)
        iidui = div(iidui_count * 100, ni)
@@ -1043,7 +949,7 @@ do
                inheritanceCSV.add_line("SL -> UD", "", 0, 0, 0, 0, slinhfud, slccifud, slicifud, sliiifud)
                inheritanceCSV.add_line("UD -> *", "", uddui, udccdui, udcidui, udiidui, udinhf, udccif, udicif, udiiif)
                inheritanceCSV.add_line("UD -> SL", "", udduisl, udccduisl, udciduisl, udiiduisl, 0, 0, 0, 0)
-               inheritanceCSV.add_line("UD -> UD", "", udduiud, udccduiud, udciduiud, udiiduiud, udinhfud, udccifud, udicifud, udiiifud)
+               inheritanceCSV.add_line("UD -> UD", ditud, udduiud, udccduiud, udciduiud, udiiduiud, udinhfud, udccifud, udicifud, udiiifud)
                for m in model.mmodules do
                        if m.intro_mclasses.is_empty and m.in_nesting.greaters.length == 1 then continue
                        inheritanceCSV.add_line(m.name, m.dit, m.dui, m.ccdui, m.cidui, m.iidui, m.inhf, m.ccif, m.icif, m.iiif)
@@ -1149,5 +1055,4 @@ do
 end
 
 # TODO Third-Party metrics
-# TODO CSV generation
 # TODO gnu-plot generation