nitmetrics: add specifiv genericity metrics
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 11 Dec 2012 01:45:59 +0000 (20:45 -0500)
committerJean Privat <jean@pryen.org>
Thu, 24 Jan 2013 22:38:06 +0000 (17:38 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/metrics/genericity_metrics.nit [new file with mode: 0644]
src/metrics/inheritance_metrics.nit
src/metrics/metrics.nit
src/metrics/metrics_base.nit
src/nitmetrics.nit

diff --git a/src/metrics/genericity_metrics.nit b/src/metrics/genericity_metrics.nit
new file mode 100644 (file)
index 0000000..d24ac99
--- /dev/null
@@ -0,0 +1,264 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Collect metrics about genericity usage
+module genericity_metrics
+
+private import metrics_base
+private import inheritance_metrics
+
+redef class MClass
+       # Inheritance
+       private var nogp: Int = 0               # (NOP) Number of generic parents (direct superclasses)
+       private var nogpc: Int = 0              # (NOPC) Number of generic class parents
+       private var nogpi: Int = 0              # (NOPI) Number of generic interface parents
+       private var noga: Int = 0               # (NOA) Number of generic ancestors (direct and indirect)
+       private var nogac: Int = 0              # (NOAC) Number of generic class ancestors
+       private var nogai: Int = 0              # (NOAI) Number of generic interface ancestors
+       private var nogc: Int = 0       # (NOC) Number of generic children (direct subclasses)
+       private var nogcc: Int = 0              # (NOCC) Number of generic class children
+       private var nogci: Int = 0              # (NOCI) Number of generic interface children
+       private var nogd: Int = 0       # (NOD) Number of generic descendants (direct and indirect)
+       private var nogdc: Int = 0              # (NODC) Number of generic class descendants
+       private var nogdi: Int = 0              # (NODI) Number of generic interface descendants
+       private var ditg: Int = 0               # (DIT) Length of longest path to the root hierarchy and consisting only of generic edges
+       private var ditgc: Int = 0              # (DITC) Length of longest path to the root hierarchy and consisting only of generic extends edges
+       private var ditgi: Int = 0              # (DITI) Length of longest path to the root hierarchy and consisting only of generic implements edges
+
+       # User Defined inheritance
+       private var nogpud: Int = 0             # (NOPUD) Number of parents (direct superclasses)
+       private var nogpcud: Int = 0    # (NOPCUD) Number of class parents
+       private var nogpiud: Int = 0    # (NOPIUD) Number of interface parents
+       private var nogaud: Int = 0             # (NOAUD) Number of ancestors (direct and indirect)
+       private var nogacud: Int = 0    # (NOACUD) Number of class ancestors
+       private var nogaiud: Int = 0    # (NOAIUD) Number of interface ancestors
+       private var nogcud: Int = 0     # (NOCUD) Number of children (direct subclasses)
+       private var nogccud: Int = 0    # (NOCCUD) Number of class children
+       private var nogciud: Int = 0    # (NOCIUD) Number of interface children
+       private var nogdud: Int = 0     # (NODUD) Number of descendants (direct and indirect)
+       private var nogdcud: Int = 0    # (NODCUD) Number of class descendants
+       private var nogdiud: Int = 0    # (NODIUD) Number of interface descendants
+       private var ditgud: Int = 0             # (DITUD) Depth in Inheritance Tree (maximum distance to root of the hierarchy)
+       private var ditgcud: Int = 0    # (DITCUD) Length of longest path to the root hierarchy and consisting only of extends edges
+       private var ditgiud: Int = 0    # (DITIUD) Length of longest path to the root hierarchy and consisting only of extends implements
+
+       private fun compute_class_genericity_metrics(model: Model) do
+               # inheritance metrics
+               self.nogp = model.extract_generics(parents).length
+               self.nogpc = model.extract_generics(model.extract_classes(parents)).length
+               self.nogpi = model.extract_generics(model.extract_interfaces(parents)).length
+               self.noga = model.extract_generics(ancestors).length
+               self.nogac = model.extract_generics(model.extract_classes(ancestors)).length
+               self.nogai = model.extract_generics(model.extract_interfaces(ancestors)).length
+               self.nogc = model.extract_generics(children(model)).length
+               self.nogcc = model.extract_generics(model.extract_classes(children(model))).length
+               self.nogci = model.extract_generics(model.extract_interfaces(children(model))).length
+               self.nogd = model.extract_generics(descendants).length
+               self.nogdc = model.extract_generics(model.extract_classes(descendants)).length
+               self.nogdi = model.extract_generics(model.extract_interfaces(descendants)).length
+               self.ditg = gen_path_to_object.length
+               self.ditgc = gen_class_path_to_object.length
+               self.ditgi = gen_interface_path_to_object.length
+
+               # used defined metrics
+               self.nogpud = model.extract_generics(model.extract_user_defined(parents)).length
+               self.nogpcud = model.extract_generics(model.extract_user_defined(model.extract_classes(parents))).length
+               self.nogpiud = model.extract_generics(model.extract_user_defined(model.extract_interfaces(parents))).length
+               self.nogaud = model.extract_generics(model.extract_user_defined(ancestors)).length
+               self.nogacud = model.extract_generics(model.extract_user_defined(model.extract_classes(ancestors))).length
+               self.nogaiud = model.extract_generics(model.extract_user_defined(model.extract_interfaces(ancestors))).length
+               self.nogcud = model.extract_generics(model.extract_user_defined(children(model))).length
+               self.nogccud = model.extract_generics(model.extract_user_defined(model.extract_classes(children(model)))).length
+               self.nogciud = model.extract_generics(model.extract_user_defined(model.extract_interfaces(children(model)))).length
+               self.nogdud = model.extract_generics(model.extract_user_defined(descendants)).length
+               self.nogdcud = model.extract_generics(model.extract_user_defined(model.extract_classes(descendants))).length
+               self.nogdiud = model.extract_generics(model.extract_user_defined(model.extract_interfaces(descendants))).length
+               self.ditgud = model.extract_generics(model.extract_user_defined(path_to_object)).length
+               self.ditgcud = model.extract_generics(model.extract_user_defined(model.extract_classes(path_to_object))).length
+               self.ditgiud = model.extract_generics(model.extract_user_defined(model.extract_interfaces(path_to_object))).length
+       end
+
+       # Return the longest path from class to root hierarchy following only generic relations
+       fun gen_path_to_object: Array[MClass] do
+               var path = new Array[MClass]
+               if not self.arity > 0 then return path
+               var max_dit: nullable Int = null
+               var max_parent: nullable MClass = null
+               var parent_path: nullable Array[MClass] = null
+
+               for p in parents do
+                       var dit = p.gen_path_to_object.length
+                       if max_dit == null or dit >= max_dit then
+                               max_dit = dit
+                               max_parent = p
+                               parent_path = p.gen_path_to_object
+                       end
+               end
+
+               if max_parent != null and parent_path != null then
+                       path.add(max_parent)
+                       path.add_all(parent_path)
+               end
+
+               return path
+       end
+
+       # Return the longest path from class to root hierarchy following only classes relations
+       fun gen_class_path_to_object: Array[MClass] do
+               var path = new Array[MClass]
+               if not self.is_class or not self.arity > 0 then return path
+               var max_dit: nullable Int = null
+               var max_parent: nullable MClass = null
+               var parent_path: nullable Array[MClass] = null
+
+               for p in parents do
+                       var dit = p.gen_class_path_to_object.length
+                       if max_dit == null or dit >= max_dit then
+                               max_dit = dit
+                               max_parent = p
+                               parent_path = p.gen_class_path_to_object
+                       end
+               end
+
+               if max_parent != null and parent_path != null then
+                       path.add(max_parent)
+                       path.add_all(parent_path)
+               end
+
+               return path
+       end
+
+       # Return the longest path from class to root hierarchy following only interfaces relations
+       fun gen_interface_path_to_object: Array[MClass] do
+               var path = new Array[MClass]
+               if not self.is_interface or not self.arity > 0 then return path
+               var max_dit: nullable Int = null
+               var max_parent: nullable MClass = null
+               var parent_path: nullable Array[MClass] = null
+
+               for p in parents do
+                       var dit = p.gen_interface_path_to_object.length
+                       if max_dit == null or dit >= max_dit then
+                               max_dit = dit
+                               max_parent = p
+                               parent_path = p.gen_interface_path_to_object
+                       end
+               end
+
+               if max_parent != null and parent_path != null then
+                       path.add(max_parent)
+                       path.add_all(parent_path)
+               end
+
+               return path
+       end
+end
+
+redef class MModule
+
+       private var gdit = ""                   # (DIT) Global Depth in Inheritance Tree
+       private var gdui = ""                   # (DUI) Proportion of types that either implement an interface or extend another type other than Object
+       private var gccdui = ""                         # (CCDUI) Proportion of classes that extend some other class.
+       private var gcidui = ""                         # (CIDUI) Proportion of classes that implement some other interface.
+       private var giidui = ""                         # (IIDUI) Proportion of interfaces that extend some other interface.
+       private var ginhf = ""                  # (IF) Proportion of types Inherited From, that is, those types that are either extended or implemented
+       private var gccif = ""                  # (CCIF) Proportion of classes extended by some other class.
+       private var gicif = ""                  # (ICIF) Proportion of interfaces implemented by some other class.
+       private var giiif = ""                  # (IIIF) Proportion of interfaces extended by some other interface.
+
+       fun compute_module_genericity_metrics(model: Model) do
+               var ditsum = 0
+               var dui_count = 0
+               var ccdui_count = 0
+               var cidui_count = 0
+               var iidui_count = 0
+               var if_count = 0
+               var ccif_count = 0
+               var icif_count = 0
+               var iiif_count = 0
+
+               for mmodule in self.in_nesting.greaters do
+                       for mclass in mmodule.intro_mclasses do
+                               if not mclass.arity > 0 then continue
+                               ditsum += mclass.gen_path_to_object.length
+                               if mclass.arity > 0 and mclass.is_dui_eligible then dui_count += 1
+                               if mclass.arity > 0 and mclass.is_ccdui_eligible then ccdui_count += 1
+                               if mclass.arity > 0 and mclass.is_cidui_eligible then cidui_count += 1
+                               if mclass.arity > 0 and mclass.is_iidui_eligible then iidui_count += 1
+                               if mclass.arity > 0 and mclass.is_if_eligible(model) then if_count += 1
+                               if mclass.arity > 0 and mclass.is_ccif_eligible(model) then ccif_count += 1
+                               if mclass.arity > 0 and mclass.is_icif_eligible(model) then icif_count += 1
+                               if mclass.arity > 0 and mclass.is_iiif_eligible(model) then iiif_count += 1
+                       end
+               end
+
+               gdit = div(ditsum, ngc + ngi)
+               gdui = div(dui_count * 100, ngc + ngi)
+               gccdui = div(ccdui_count * 100, ngc)
+               gcidui = div(cidui_count * 100, ngc)
+               giidui = div(iidui_count * 100, ngi)
+               ginhf = div(if_count * 100, ngc + ngi)
+               gccif = div(ccif_count * 100, ngc)
+               gicif = div(icif_count * 100, ngi)
+               giiif = div(iiif_count * 100, ngi)
+       end
+end
+
+# Print inheritance usage metrics
+fun compute_genericity_metrics(toolcontext: ToolContext, model: Model)
+do
+       compute_inheritance_metrics(toolcontext, model)
+
+       # compute modules scalar metrics
+       for mmodule in model.mmodules do
+               mmodule.compute_module_genericity_metrics(model)
+       end
+
+       # compute class scalar metrics
+       for mclass in model.mclasses do
+               mclass.compute_class_genericity_metrics(model)
+       end
+
+       #TODO Comment monitorer l'évolution de la signature générique ? C[T, U] <: B <: A[V]
+
+       # CSV generation
+       if toolcontext.opt_generate_csv.value then
+               # inheritance metrics
+               var inheritanceCSV = new CSVDocument(toolcontext.output_dir.join_path("inheritance_genericity_metrics.csv"))
+               inheritanceCSV.set_header("scope", "GDIT", "GDUI", "GCCDUI", "GCIDUI", "GIIDUI", "GIF", "GCCIF", "GICIF", "GIIIF")
+               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.gdit, m.gdui, m.gccdui, m.gcidui, m.giidui, m.ginhf, m.gccif, m.gicif, m.giiif)
+               end
+               inheritanceCSV.save
+
+               # scalar metrics
+               var scalarCSV = new CSVDocument(toolcontext.output_dir.join_path("global_scalar_generic_metrics.csv"))
+               var udscalarCSV = new CSVDocument(toolcontext.output_dir.join_path("ud_scalar_generic_metrics.csv"))
+               scalarCSV.set_header("mclass", "type", "FT", "DITG", "DITGC", "DITGI", "NOGP", "NOGPC", "NOGPI", "NOGA", "NOGAC", "NOGAI", "NOGC", "NOGCC", "NOGCI", "NOGD", "NOGDC", "NOGDI")
+               udscalarCSV.set_header("mclass", "type", "FT", "DITGUD", "DITGCUD", "DITGIUD", "NOGPUD", "NOGPCUD", "NOGPIUD", "NOGAUD", "NOGACUD", "NOGAIUD", "NOGCUD", "NOGCCUD", "NOGCIUD", "NOGDUD", "NOGDCUD", "NOGDIUD")
+               for c in model.mclasses do
+                       if not c.arity > 0 then continue
+                       var name = c.name
+                       var typ = "class"
+                       if c.is_interface then typ = "interface"
+                       scalarCSV.add_line(name, typ, c.arity, c.ditg, c.ditgc, c.ditgi, c.nogp, c.nogpc, c.nogpi, c.noga, c.nogac, c.nogai, c.nogc, c.nogcc, c.nogci, c.nogd, c.nogdc, c.nogdi)
+                       udscalarCSV.add_line(name, typ, c.arity, c.ditgud, c.ditgcud, c.ditgiud, c.nogpud, c.nogpcud, c.nogpiud, c.nogaud, c.nogacud, c.nogaiud, c.nogcud, c.nogccud, c.nogciud, c.nogdud, c.nogdcud, c.nogdiud)
+               end
+               scalarCSV.save
+               udscalarCSV.save
+       end
+end
index 935cc47..99408d4 100644 (file)
@@ -179,24 +179,24 @@ redef class MClass
                self.ditiud = ud_interface_path_to_object.length
        end
 
-       private fun is_class: Bool do
+       fun is_class: Bool do
                return self.kind == concrete_kind or self.kind == abstract_kind
        end
 
-       private fun is_interface: Bool do
+       fun is_interface: Bool do
                return self.kind == interface_kind
        end
 
-       private fun is_abstract: Bool do
+       fun is_abstract: Bool do
                return self.kind == abstract_kind
        end
 
-       private fun is_user_defined: Bool do
+       fun is_user_defined: Bool do
                return self.intro_mmodule.is_user_defined
        end
 
        # Get parents of the class (direct super classes only)
-       private fun parents: Set[MClass] do
+       fun parents: Set[MClass] do
                var lst = new HashSet[MClass]
                # explore all definitions of the class (refinement)
                for mclassdef in self.mclassdefs do
@@ -208,7 +208,7 @@ redef class MClass
        end
 
        # Get ancestors of the class (all super classes)
-       private fun ancestors: Set[MClass] do
+       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
@@ -220,7 +220,7 @@ redef class MClass
        end
 
        # Get children of the class (direct subclasses only)
-       private fun children(model: Model): Set[MClass] do
+       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
@@ -232,7 +232,7 @@ redef class MClass
        end
 
        # Get children of the class (direct subclasses only)
-       private fun descendants: Set[MClass] do
+       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
@@ -266,6 +266,7 @@ redef class MClass
 
                return path
        end
+
        # Return the longest path from class to root hierarchy
        fun ud_path_to_object: Array[MClass] do
                var path = new Array[MClass]
@@ -393,37 +394,37 @@ redef class MClass
 
        # * -> * DUI
 
-       private fun is_dui_eligible: Bool do
+       fun is_dui_eligible: Bool do
                for parent in parents do if parent.name != "Object" then return true
                return false
        end
-       private fun is_ccdui_eligible: Bool do
+       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
-       private fun is_cidui_eligible: Bool do
+       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
-       private fun is_iidui_eligible: Bool do
+       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
-       private fun is_if_eligible(model: Model): Bool do return not children(model).is_empty
-       private fun is_ccif_eligible(model: Model): Bool do
+       fun is_if_eligible(model: Model): Bool do return not children(model).is_empty
+       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
                return false
        end
-       private fun is_icif_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_iiif_eligible(model: Model): Bool do
+       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
                return false
@@ -431,46 +432,46 @@ redef class MClass
 
        # SL -> * DUI
 
-       private fun is_sldui_eligible: Bool do
+       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
-       private fun is_slccdui_eligible: Bool do
+       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
-       private fun is_slcidui_eligible: Bool do
+       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
-       private fun is_sliidui_eligible: Bool do
+       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
-       private fun is_slif_eligible(model: Model): Bool do
+       fun is_slif_eligible(model: Model): Bool do
                if is_user_defined then return false
                return not children(model).is_empty
        end
-       private fun is_slccif_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_slicif_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_sliiif_eligible(model: Model): Bool do
+       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
@@ -479,24 +480,24 @@ redef class MClass
 
        # SL -> SL
 
-       private fun is_slifsl_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_slccifsl_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_slicifsl_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_sliiifsl_eligible(model: Model): Bool do
+       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
@@ -505,24 +506,24 @@ redef class MClass
 
        # SL -> UD
 
-       private fun is_slifud_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_slccifud_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_slicifud_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_sliiifud_eligible(model: Model): Bool do
+       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
@@ -531,46 +532,46 @@ redef class MClass
 
        # UD -> *
 
-       private fun is_uddui_eligible: Bool do
+       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
-       private fun is_udccdui_eligible: Bool do
+       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
-       private fun is_udcidui_eligible: Bool do
+       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
-       private fun is_udiidui_eligible: Bool do
+       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
-       private fun is_udif_eligible(model: Model): Bool do
+       fun is_udif_eligible(model: Model): Bool do
                if not is_user_defined then return false
                return not children(model).is_empty
        end
-       private fun is_udccif_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_udicif_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_udiiif_eligible(model: Model): Bool do
+       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
@@ -579,24 +580,24 @@ redef class MClass
 
        # UD -> SL
 
-       private fun is_udduisl_eligible: Bool do
+       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
-       private fun is_udccduisl_eligible: Bool do
+       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
-       private fun is_udciduisl_eligible: Bool do
+       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
-       private fun is_udiiduisl_eligible: Bool do
+       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
@@ -605,46 +606,46 @@ redef class MClass
 
        # UD -> UD
 
-       private fun is_udduiud_eligible: Bool do
+       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
-       private fun is_udccduiud_eligible: Bool do
+       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
-       private fun is_udciduiud_eligible: Bool do
+       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
-       private fun is_udiiduiud_eligible: Bool do
+       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
-       private fun is_udifud_eligible(model: Model): Bool do
+       fun is_udifud_eligible(model: Model): Bool do
                if not is_user_defined then return false
                return not children(model).is_empty
        end
-       private fun is_udccifud_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_udicifud_eligible(model: Model): Bool do
+       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
                return false
        end
-       private fun is_udiiifud_eligible(model: Model): Bool do
+       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
@@ -659,8 +660,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
-       private var ngc : Int = 0               # (NGC) Number of Generic Classes
-       private var ngi : Int = 0               # (NGI) Number of Generic Interfaces
+       protected var ngc : Int = 0             # (NGC) Number of Generic Classes
+       protected 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
@@ -672,7 +673,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.
 
-       private fun compute_module_inheritance_metrics(model: Model) do
+       fun compute_module_inheritance_metrics(model: Model) do
                var ditsum = 0
                var dui_count = 0
                var ccdui_count = 0
@@ -715,7 +716,7 @@ redef class MModule
                iiif = div(iiif_count * 100, ni)
        end
 
-       private fun is_user_defined: Bool do
+       fun is_user_defined: Bool do
                return not self.model.std_modules.has(self.name)
        end
 end
index e49fdb5..edd9913 100644 (file)
@@ -19,6 +19,7 @@ module metrics
 
 import metrics_base
 import inheritance_metrics
+import genericity_metrics
 import refinement_metrics
 import static_types_metrics
 import nullables_metrics
index 86d4953..b691f26 100644 (file)
@@ -26,6 +26,8 @@ redef class ToolContext
 
        # --inheritance
        var opt_inheritance = new OptionBool("Compute metrics about inheritance usage", "--inheritance")
+       # --genericity
+       var opt_genericity = new OptionBool("Compute metrics about genericity usage", "--genericity")
        # --refinement
        var opt_refinement = new OptionBool("Compute metrics about refinement usage", "--refinement")
        # --self
@@ -51,6 +53,7 @@ redef class ToolContext
                super
                self.option_context.add_option(opt_all)
                self.option_context.add_option(opt_inheritance)
+               self.option_context.add_option(opt_genericity)
                self.option_context.add_option(opt_refinement)
                self.option_context.add_option(opt_self)
                self.option_context.add_option(opt_nullables)
index 561d84c..dd88504 100644 (file)
@@ -64,6 +64,12 @@ if all or toolcontext.opt_inheritance.value then
        compute_inheritance_metrics(toolcontext, model)
 end
 
+# Genericity usage metrics
+if all or toolcontext.opt_genericity.value then
+       print ""
+       compute_genericity_metrics(toolcontext, model)
+end
+
 # Refinement usage metrics
 if all or toolcontext.opt_refinement.value then
        print ""