nitmetrics: add CVS output facilities for inheritance metrics
authorAlexandre Terrasa <alexadre@moz-code.org>
Mon, 5 Nov 2012 15:40:21 +0000 (10:40 -0500)
committerJean Privat <jean@pryen.org>
Tue, 6 Nov 2012 04:52:40 +0000 (23:52 -0500)
Signed-off-by: Alexandre Terrasa <alexadre@moz-code.org>

src/metrics/inheritance_metrics.nit
src/metrics/metrics_base.nit
src/nitmetrics.nit

index dab0e83..f9b0b15 100644 (file)
@@ -269,7 +269,8 @@ redef class MClass
                return path
        end
 
-       # DUI
+       # * -> * DUI
+
        private fun is_dui_eligible: Bool do
                for parent in parents do if parent.name != "Object" then return true
                return false
@@ -289,203 +290,249 @@ redef class MClass
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-
-       # SLDUI
-       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
-       private fun is_slccdui_eligible: Bool do
+       private fun is_if_eligible(model: Model): Bool do return not children(model).is_empty
+       private fun is_ccif_eligible(model: Model): Bool do
                if not is_class then return false
-               if is_user_defined then return false
-               for parent in parents do if parent.name != "Object" and parent.is_class then return true
+               for child in children(model) do if child.is_class then return true
                return false
        end
-       private fun is_slcidui_eligible: Bool do
-               if not is_class then return false
-               if is_user_defined then return false
-               for parent in parents do if parent.name != "Object" and parent.is_interface then return true
+       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
                return false
        end
-       private fun is_sliidui_eligible: Bool do
+       private fun is_iiif_eligible(model: Model): Bool do
                if not is_interface then return false
-               if is_user_defined then return false
-               for parent in parents do if parent.name != "Object" and parent.is_interface then return true
+               for child in children(model) do if child.is_interface then return true
                return false
        end
 
-       # UDDUI
+       # SL -> * DUI
 
-       private fun is_uddui_eligible: Bool do
-               if not is_user_defined then return false
+       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
-       private fun is_udccdui_eligible: Bool do
+       private fun is_slccdui_eligible: Bool do
+               if is_user_defined then return false
                if not is_class then return false
-               if not is_user_defined 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
+       private fun is_slcidui_eligible: Bool do
+               if is_user_defined then return false
                if not is_class then return false
-               if not is_user_defined 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
+       private fun is_sliidui_eligible: Bool do
+               if is_user_defined then return false
                if not is_interface then return false
-               if not is_user_defined then return false
                for parent in parents do if parent.name != "Object" and parent.is_interface then return true
                return false
        end
-
-       # UDDUIUD
-
-       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
-       private fun is_udccduiud_eligible: Bool do
-               if not is_class then return false
-               if not is_user_defined 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
-               if not is_class then return false
-               if not is_user_defined 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
-               if not is_interface then return false
-               if not is_user_defined 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
-
-       # IF
-       private fun is_if_eligible(model: Model): Bool do return not children(model).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
-               return false
-       end
-       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
-               return false
-       end
-       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
-               return false
-       end
-
-       # SLIF
        private 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
-               if not is_class then return false
                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
-               if not is_interface then return false
                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
-               if not is_interface then return false
                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
                return false
        end
 
-       # SLIFSL
+       # SL -> SL
+
        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
                return false
        end
        private fun is_slccifsl_eligible(model: Model): Bool do
+               if is_user_defined then return false
                if is_class then return false
-               if not is_user_defined 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
+               if is_user_defined then return false
                if not is_interface then return false
-               if not is_user_defined 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
+               if is_user_defined then return false
                if not is_interface then return false
-               if not is_user_defined then return false
                for child in children(model) do if not child.is_user_defined and child.is_interface then return true
                return false
        end
 
-       #SLIFUD
+       # SL -> UD
+
        private fun is_slifud_eligible(model: Model): Bool do
-               if not is_user_defined then return false
+               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
+               if is_user_defined then return false
                if not is_class then return false
-               if not is_user_defined 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
+               if is_user_defined then return false
                if not is_interface then return false
-               if not is_user_defined 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
+               if is_user_defined then return false
                if not is_interface then return false
-               if not is_user_defined then return false
                for child in children(model) do if child.is_user_defined and child.is_interface then return true
                return false
        end
 
-       # UDIF
+       # UD -> *
+
+       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
+       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
+       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
+       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
        private 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
-               if not is_class then return false
                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
-               if not is_interface then return false
                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
-               if not is_interface then return false
                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
                return false
        end
+
+       # UD -> SL
+
+       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
+       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
+       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
+       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
+               return false
+       end
+
+       # UD -> UD
+
+       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
+       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
+       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
+       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
+       private 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
+               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
+               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
+               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
+               return false
+       end
+
 end
 
 # Print inheritance usage metrics
-fun compute_inheritance_metrics(model: Model)
+fun compute_inheritance_metrics(toolcontext: ToolContext, model: Model)
 do
        # global summary metrics
        var nmd: Int = 0                        # (NMD) Number of Modules
@@ -511,56 +558,62 @@ do
 
        # global summary inheritance metrics
        var dit = ""                            # (DIT) Global Depth in Inheritance Tree
-       # dui
-       var dui = ""                            # (DUI) The proportion of types that either implement an interface or extend another type other than Object
-       var ccdui = ""                          # (CCDUI) The proportion of classes that extend some other class.
-       var cidui = ""                          # (CIDUI) The proportion of classes that implement some other interface.
-       var iidui = ""                          # (IIDUI) The proportion of interfaces that extend some other interface.
-       # if
-       var inhf = ""                           # (IF) The proportion of types Inherited From, that is, those types that are either extended or implemented
-       var ccif = ""                           # (CCIF) The proportion of classes extended by some other class.
-       var icif = ""                           # (ICIF) The proportion of interfaces implemented by some other class.
-       var iiif = ""                           # (IIIF) The proportion of interfaces extended by some other interface.
-
-       # (SL) Std-Lib summary inheritance metrics
-       # sl dui
-       var sldui = ""                          # (SLDUI) The proportion of std-lib types that either implement an interface or extend another std-lib type other than Object
-       var slccdui = ""                        # (SLCCDUI) The proportion of std-lib classes that extend some other std-lib class.
-       var slcidui = ""                        # (SLCIDUI) The proportion of std-lib classes that implement some other std-lib interface.
-       var sliidui = ""                        # (SLIIDUI) The proportion of std-lib interfaces that extend some other std-lib interface.
-       # sl if
-       var slinhf = ""                         # (SLIF) The proportion of SL types Inherited From, that is, those types that are either extended or implemented
-       var slccif = ""                         # (SLCCIF) The proportion of SL classes extended by some other class.
-       var slicif = ""                         # (SLICIF) The proportion of SL interfaces implemented by some other class.
-       var sliiif = ""                         # (SLIIIF) The proportion of SL interfaces extended by some other interface.
-       # sl if sl
-       var slinhfsl = ""                               # (SLIFSL) The proportion of SL types Inherited From, that is, those types that are either extended or implemented by a SL type
-       var slccifsl = ""                               # (SLCCIFSL) The proportion of SL classes extended by some other SL class.
-       var slicifsl = ""                               # (SLICIFSL) The proportion of SL interfaces implemented by some other SL class.
-       var sliiifsl = ""                               # (SLIIIFSL) The proportion of SL interfaces extended by some other SL interface.
-       # sl if ud
-       var slinhfud = ""                               # (SLIFUD) The proportion of SL types Inherited From, that is, those types that are either extended or implemented by a UD type
-       var slccifud = ""                               # (SLCCIFUD) The proportion of SL classes extended by some other UD class.
-       var slicifud = ""                               # (SLICIFUD) The proportion of SL interfaces implemented by some other UD class.
-       var sliiifud = ""                               # (SLIIIFUD) The proportion of SL interfaces extended by some other UD interface.
-
-       # (UD) User-defined summary inheritance metrics
-       #dui
-       var uddui = ""                          # (UDDUI) The proportion user-defined of types that either implement an interface or extend another type
-       var udccdui = ""                        # (UDCCDUI) The proportion of user-defined classes that extend some other class.
-       var udcidui = ""                        # (UDCIDUI) The proportion of user-defined classes that implement some other interface.
-       var udiidui = ""                        # (UDIIDUI) The proportion of user-defined interfaces that extend some other interface.
-       # ud if
-       var udinhf = ""                         # (UDIF) The proportion of UD types Inherited From, that is, those types that are either extended or implemented
-       var udccif = ""                         # (UDCCIF) The proportion of UD classes extended by some other class.
-       var udicif = ""                         # (UDICIF) The proportion of UD interfaces implemented by some other class.
-       var udiiif = ""                         # (UDIIIF) The proportion of UD interfaces extended by some other interface.
-
-       # (UD*UD) User-defined summary inheritance metrics
-       var udduiud = ""                        # (UDDUIUD) The proportion user-defined of types that either implement an interface or extend another type user-defined
-       var udccduiud = ""                      # (UDCCDUIUD) The proportion of user-defined classes that extend some other user-defined class.
-       var udciduiud = ""                      # (UDCIDUIUD) The proportion of user-defined classes that implement some other user-defined interface.
-       var udiiduiud = ""                      # (UDIIDUIUD) The proportion of user-defined interfaces that extend some other user-defined interface.
+       var dui = ""                            # (DUI) Proportion of types that either implement an interface or extend another type other than Object
+       var ccdui = ""                          # (CCDUI) Proportion of classes that extend some other class.
+       var cidui = ""                          # (CIDUI) Proportion of classes that implement some other interface.
+       var iidui = ""                          # (IIDUI) Proportion of interfaces that extend some other interface.
+       var inhf = ""                           # (IF) Proportion of types Inherited From, that is, those types that are either extended or implemented
+       var ccif = ""                           # (CCIF) Proportion of classes extended by some other class.
+       var icif = ""                           # (ICIF) Proportion of interfaces implemented by some other class.
+       var iiif = ""                           # (IIIF) Proportion of interfaces extended by some other interface.
+
+       # (SL -> *) Std-Lib summary inheritance metrics
+       var sldui = ""                          # (SLDUI) Proportion of std-lib types that either implement an interface or extend another std-lib type other than Object
+       var slccdui = ""                        # (SLCCDUI) Proportion of std-lib classes that extend some other std-lib class.
+       var slcidui = ""                        # (SLCIDUI) Proportion of std-lib classes that implement some other std-lib interface.
+       var sliidui = ""                        # (SLIIDUI) Proportion of std-lib interfaces that extend some other std-lib interface.
+       var slinhf = ""                         # (SLIF) Proportion of SL types Inherited From, that is, those types that are either extended or implemented
+       var slccif = ""                         # (SLCCIF) Proportion of SL classes extended by some other class.
+       var slicif = ""                         # (SLICIF) Proportion of SL interfaces implemented by some other class.
+       var sliiif = ""                         # (SLIIIF) Proportion of SL interfaces extended by some other interface.
+
+       # (SL -> SL) Std-Lib summary inheritance metrics
+       var slinhfsl = ""                               # (SLIFSL) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a SL type
+       var slccifsl = ""                               # (SLCCIFSL) Proportion of SL classes extended by some other SL class.
+       var slicifsl = ""                               # (SLICIFSL) Proportion of SL interfaces implemented by some other SL class.
+       var sliiifsl = ""                               # (SLIIIFSL) Proportion of SL interfaces extended by some other SL interface.
+
+       # (SL -> UD) Std-Lib summary inheritance metrics
+       var slinhfud = ""                               # (SLIFUD) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a UD type
+       var slccifud = ""                               # (SLCCIFUD) Proportion of SL classes extended by some other UD class.
+       var slicifud = ""                               # (SLICIFUD) Proportion of SL interfaces implemented by some other UD class.
+       var sliiifud = ""                               # (SLIIIFUD) Proportion of SL interfaces extended by some other UD interface.
+
+       # (UD -> *) User-defined summary inheritance metrics
+       var uddui = ""                          # (UDDUI) Proportion user-defined of types that either implement an interface or extend another type
+       var udccdui = ""                        # (UDCCDUI) Proportion of user-defined classes that extend some other class.
+       var udcidui = ""                        # (UDCIDUI) Proportion of user-defined classes that implement some other interface.
+       var udiidui = ""                        # (UDIIDUI) Proportion of user-defined interfaces that extend some other interface.
+       var udinhf = ""                         # (UDIF) Proportion of UD types Inherited From, that is, those types that are either extended or implemented
+       var udccif = ""                         # (UDCCIF) Proportion of UD classes extended by some other class.
+       var udicif = ""                         # (UDICIF) Proportion of UD interfaces implemented by some other class.
+       var udiiif = ""                         # (UDIIIF) Proportion of UD interfaces extended by some other interface.
+
+       # (UD -> SL) User-defined summary inheritance metrics
+       var udduisl = ""                        # (UDDUISL) Proportion user-defined of types that either implement an interface or extend another type SL
+       var udccduisl = ""                      # (UDCCDUISL) Proportion of user-defined classes that extend some other SL class.
+       var udciduisl = ""                      # (UDCIDUISL) Proportion of user-defined classes that implement some other SL interface.
+       var udiiduisl = ""                      # (UDIIDUISL) Proportion of user-defined interfaces that extend some other SL interface.
+
+       # (UD -> UD) User-defined summary inheritance metrics
+       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.
+       var udiiduiud = ""                      # (UDIIDUIUD) Proportion of user-defined interfaces that extend some other user-defined interface.
+       var udinhfud = ""                       # (UDIFUD) Proportion of UD types Inherited From, that is, those types that are either extended or implemented by another UD type
+       var udccifud = ""                       # (UDCCIFUD) Proportion of UD classes extended by some other UD class.
+       var udicifud = ""                       # (UDICIFUD) Proportion of UD interfaces implemented by some other UD class.
+       var udiiifud = ""                       # (UDIIIFUD) Proportion of UD interfaces extended by some other UD interface.
 
        # compute scalar metrics
        for mclass in model.mclasses do
@@ -593,149 +646,224 @@ do
 
        # compute inheritance summary metrics
 
+       # * -> *
        var ditsum = 0
-
        var dui_count = 0
        var ccdui_count = 0
        var cidui_count = 0
        var iidui_count = 0
-
-       var sldui_count = 0
-       var slccdui_count = 0
-       var slcidui_count = 0
-       var sliidui_count = 0
-
-       var uddui_count = 0
-       var udccdui_count = 0
-       var udcidui_count = 0
-       var udiidui_count = 0
-
-       var udduiud_count = 0
-       var udccduiud_count = 0
-       var udciduiud_count = 0
-       var udiiduiud_count = 0
-
        var if_count = 0
        var ccif_count = 0
        var icif_count = 0
        var iiif_count = 0
 
+       # SL -> *
+       var sldui_count = 0
+       var slccdui_count = 0
+       var slcidui_count = 0
+       var sliidui_count = 0
        var slif_count = 0
        var slccif_count = 0
        var slicif_count = 0
        var sliiif_count = 0
 
+       # SL -> SL
        var slifsl_count = 0
        var slccifsl_count = 0
        var slicifsl_count = 0
        var sliiifsl_count = 0
 
+       # SL -> UD
        var slifud_count = 0
        var slccifud_count = 0
        var slicifud_count = 0
        var sliiifud_count = 0
 
+       # UD -> *
+       var uddui_count = 0
+       var udccdui_count = 0
+       var udcidui_count = 0
+       var udiidui_count = 0
        var udif_count = 0
        var udccif_count = 0
        var udicif_count = 0
        var udiiif_count = 0
 
+       # UD -> SL
+       var udduisl_count = 0
+       var udccduisl_count = 0
+       var udciduisl_count = 0
+       var udiiduisl_count = 0
+
+       # UD -> UD
+       var udduiud_count = 0
+       var udccduiud_count = 0
+       var udciduiud_count = 0
+       var udiiduiud_count = 0
+       var udifud_count = 0
+       var udccifud_count = 0
+       var udicifud_count = 0
+       var udiiifud_count = 0
 
        for mclass in model.mclasses do
                ditsum += mclass.dit
 
+               # * -> *
                if mclass.is_dui_eligible then dui_count += 1
                if mclass.is_ccdui_eligible then ccdui_count += 1
                if mclass.is_cidui_eligible then cidui_count += 1
                if mclass.is_iidui_eligible then iidui_count += 1
-
-               if mclass.is_sldui_eligible then sldui_count += 1
-               if mclass.is_slccdui_eligible then slccdui_count += 1
-               if mclass.is_slcidui_eligible then slcidui_count += 1
-               if mclass.is_sliidui_eligible then sliidui_count += 1
-
-               if mclass.is_uddui_eligible then uddui_count += 1
-               if mclass.is_udccdui_eligible then udccdui_count += 1
-               if mclass.is_udcidui_eligible then udcidui_count += 1
-               if mclass.is_udiidui_eligible then udiidui_count += 1
-
-               if mclass.is_udduiud_eligible then udduiud_count += 1
-               if mclass.is_udccduiud_eligible then udccduiud_count += 1
-               if mclass.is_udciduiud_eligible then udciduiud_count += 1
-               if mclass.is_udiiduiud_eligible then udiiduiud_count += 1
-
                if mclass.is_if_eligible(model) then if_count += 1
                if mclass.is_ccif_eligible(model) then ccif_count += 1
                if mclass.is_icif_eligible(model) then icif_count += 1
                if mclass.is_iiif_eligible(model) then iiif_count += 1
 
+               # SL -> *
+               if mclass.is_sldui_eligible then sldui_count += 1
+               if mclass.is_slccdui_eligible then slccdui_count += 1
+               if mclass.is_slcidui_eligible then slcidui_count += 1
+               if mclass.is_sliidui_eligible then sliidui_count += 1
                if mclass.is_slif_eligible(model) then slif_count += 1
                if mclass.is_slccif_eligible(model) then slccif_count += 1
                if mclass.is_slicif_eligible(model) then slicif_count += 1
                if mclass.is_sliiif_eligible(model) then sliiif_count += 1
 
+               # SL -> SL
                if mclass.is_slifsl_eligible(model) then slifsl_count += 1
                if mclass.is_slccifsl_eligible(model) then slccifsl_count += 1
                if mclass.is_slicifsl_eligible(model) then slicifsl_count += 1
                if mclass.is_sliiifsl_eligible(model) then sliiifsl_count += 1
 
+               # SL -> UD
                if mclass.is_slifud_eligible(model) then slifud_count += 1
                if mclass.is_slccifud_eligible(model) then slccifud_count += 1
                if mclass.is_slicifud_eligible(model) then slicifud_count += 1
                if mclass.is_sliiifud_eligible(model) then sliiifud_count += 1
 
+               # UD -> *
+               if mclass.is_uddui_eligible then uddui_count += 1
+               if mclass.is_udccdui_eligible then udccdui_count += 1
+               if mclass.is_udcidui_eligible then udcidui_count += 1
+               if mclass.is_udiidui_eligible then udiidui_count += 1
                if mclass.is_udif_eligible(model) then udif_count += 1
                if mclass.is_udccif_eligible(model) then udccif_count += 1
                if mclass.is_udicif_eligible(model) then udicif_count += 1
                if mclass.is_udiiif_eligible(model) then udiiif_count += 1
+
+               # UD -> SL
+               if mclass.is_udduisl_eligible then udduisl_count += 1
+               if mclass.is_udccduisl_eligible then udccduisl_count += 1
+               if mclass.is_udciduisl_eligible then udciduisl_count += 1
+               if mclass.is_udiiduisl_eligible then udiiduisl_count += 1
+
+               # UD -> UD
+               if mclass.is_udduiud_eligible then udduiud_count += 1
+               if mclass.is_udccduiud_eligible then udccduiud_count += 1
+               if mclass.is_udciduiud_eligible then udciduiud_count += 1
+               if mclass.is_udiiduiud_eligible then udiiduiud_count += 1
+               if mclass.is_udifud_eligible(model) then udifud_count += 1
+               if mclass.is_udccifud_eligible(model) then udccifud_count += 1
+               if mclass.is_udicifud_eligible(model) then udicifud_count += 1
+               if mclass.is_udiiifud_eligible(model) then udiiifud_count += 1
        end
-       dit = div(ditsum, model.mclasses.length)
 
+       # * -> *
+       dit = div(ditsum, model.mclasses.length)
        dui = div(dui_count * 100, nc + ni)
        ccdui = div(ccdui_count * 100, nc)
        cidui = div(cidui_count * 100, nc)
        iidui = div(iidui_count * 100, ni)
-
-       sldui = div(sldui_count * 100, ncsl + nisl)
-       slccdui = div(slccdui_count * 100, ncsl)
-       slcidui = div(slcidui_count * 100, ncsl)
-       sliidui = div(sliidui_count * 100, nisl)
-
-       uddui = div(uddui_count * 100, ncud + niud)
-       udccdui = div(udccdui_count * 100, ncud)
-       udcidui = div(udcidui_count * 100, ncud)
-       udiidui = div(udiidui_count * 100, niud)
-
-       udduiud = div(udduiud_count * 100, ncud + niud)
-       udccduiud = div(udccduiud_count * 100, ncud)
-       udciduiud = div(udciduiud_count * 100, ncud)
-       udiiduiud = div(udiiduiud_count * 100, niud)
-
        inhf = div(if_count * 100, nc + ni)
        ccif = div(ccif_count * 100, nc)
        icif = div(icif_count * 100, ni)
        iiif = div(iiif_count * 100, ni)
 
+       # SL -> *
+       sldui = div(sldui_count * 100, ncsl + nisl)
+       slccdui = div(slccdui_count * 100, ncsl)
+       slcidui = div(slcidui_count * 100, ncsl)
+       sliidui = div(sliidui_count * 100, nisl)
        slinhf = div(slif_count * 100, ncsl + nisl)
        slccif = div(slccif_count * 100, ncsl)
        slicif = div(slicif_count * 100, nisl)
        sliiif = div(sliiif_count * 100, nisl)
 
+       # SL -> SL
        slinhfsl = div(slifsl_count * 100, ncsl + nisl)
        slccifsl = div(slccifsl_count * 100, ncsl)
        slicifsl = div(slicifsl_count * 100, nisl)
        sliiifsl = div(sliiifsl_count * 100, nisl)
 
+       # SL -> UD
        slinhfud = div(slifud_count * 100, ncsl + nisl)
        slccifud = div(slccifud_count * 100, ncsl)
        slicifud = div(slicifud_count * 100, nisl)
        sliiifud = div(sliiifud_count * 100, nisl)
 
+       # UD -> *
+       uddui = div(uddui_count * 100, ncud + niud)
+       udccdui = div(udccdui_count * 100, ncud)
+       udcidui = div(udcidui_count * 100, ncud)
+       udiidui = div(udiidui_count * 100, niud)
        udinhf = div(if_count * 100, ncud + niud)
        udccif = div(ccif_count * 100, ncud)
        udicif = div(icif_count * 100, niud)
        udiiif = div(iiif_count * 100, niud)
 
+       # UD -> SL
+       udduisl = div(udduisl_count * 100, ncud + niud)
+       udccduisl = div(udccduisl_count * 100, ncud)
+       udciduisl = div(udciduisl_count * 100, ncud)
+       udiiduisl = div(udiiduisl_count * 100, niud)
+
+       # UD -> UD
+       udduiud = div(udduiud_count * 100, ncud + niud)
+       udccduiud = div(udccduiud_count * 100, ncud)
+       udciduiud = div(udciduiud_count * 100, ncud)
+       udiiduiud = div(udiiduiud_count * 100, niud)
+       udinhfud = div(udifud_count * 100, ncud + niud)
+       udccifud = div(udccifud_count * 100, ncud)
+       udicifud = div(udicifud_count * 100, niud)
+       udiiifud = div(udiiifud_count * 100, niud)
+
+       # CSV generation
+       if toolcontext.opt_generate_csv.value then
+               # summary_metrics
+               var summaryCSV = new CSVDocument(toolcontext.output_dir.join_path("summary_metrics.csv"))
+               summaryCSV.set_header("scope", "NMD", "NC", "NI", "NAC", "NGC", "NGI")
+               summaryCSV.add_line("global", nmd, nc, ni, nac, ngc, ngi)
+               summaryCSV.add_line("std-lib", nmdsl, ncsl, nisl, nacsl, ngcsl, ngisl)
+               summaryCSV.add_line("user-defined", nmdud, ncud, niud, nacud, ngcud, ngiud)
+               summaryCSV.save
+
+               # inheritance metrics
+               var inheritanceCSV = new CSVDocument(toolcontext.output_dir.join_path("inheritance_metrics.csv"))
+               inheritanceCSV.set_header("scope", "DIT", "DUI", "CCDUI", "CIDUI", "IIDUI", "IF", "CCIF", "ICIF", "IIIF")
+               inheritanceCSV.add_line("global", dit, dui, ccdui, cidui, iidui, inhf, ccif, icif, iiif)
+               inheritanceCSV.add_line("SL -> *", "", sldui, slccdui, slcidui, sliidui, slinhf, slccif, slicif, sliiif)
+               inheritanceCSV.add_line("SL -> SL", "", sldui, slccdui, slcidui, sliidui, slinhfsl, slccifsl, slicifsl, sliiifsl)
+               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.save
+
+               # scalar metrics
+               var scalarCSV = new CSVDocument(toolcontext.output_dir.join_path("global_scalar_metrics.csv"))
+               var udscalarCSV = new CSVDocument(toolcontext.output_dir.join_path("ud_scalar_metrics.csv"))
+               scalarCSV.set_header("mclass", "type", "DIT", "DITC", "DITI", "NOP", "NOPC", "NOPI", "NOA", "NOAC", "NOAI", "NOC", "NOCC", "NOCI", "NOD", "NODC", "NODI")
+               udscalarCSV.set_header("mclass", "type", "DITUD", "DITCUD", "DITIUD", "NOPUD", "NOPCUD", "NOPIUD", "NOAUD", "NOACUD", "NOAIUD", "NOCUD", "NOCCUD", "NOCIUD", "NODUD", "NODCUD", "NODIUD")
+               for mclass in model.mclasses do
+                       var name = mclass.name
+                       var typ = "class"
+                       if mclass.is_interface then typ = "interface"
+                       scalarCSV.add_line(name, typ, mclass.dit, mclass.ditc, mclass.diti, mclass.nop, mclass.nopc, mclass.nopi, mclass.noa, mclass.noac, mclass.noai, mclass.noc, mclass.nocc, mclass.noci, mclass.nod, mclass.nodc, mclass.nodi)
+                       udscalarCSV.add_line(name, typ, mclass.ditud, mclass.ditcud, mclass.ditiud, mclass.nopud, mclass.nopcud, mclass.nopiud, mclass.noaud, mclass.noacud, mclass.noaiud, mclass.nocud, mclass.noccud, mclass.nociud, mclass.nodud, mclass.nodcud, mclass.nodiud)
+               end
+               scalarCSV.save
+               udscalarCSV.save
+       end
+
        print "--- Global Summary metrics ---"
        print "(NMD) Number of Modules: {nmd}"
        print "(NC)  Number of Classes: {nc}"
@@ -768,7 +896,8 @@ do
        print "(CCIF) Proportion of classes extended by class: {ccif}%"
        print "(ICIF) Proportion of interfaces implemented by class: {icif}%"
        print "(IIIF) Proportion of interfaces extended by interface: {iiif}%"
-       print "--- (SL) Std-Lib Inheritance metrics ---"
+       print ""
+       print "--- (SL -> *) Std-Lib Inheritance metrics ---"
        print "(SLDUI) Proportion of SL types inheriting another type other than Object: {sldui}%"
        print "(SLCCDUI) Proportion of SL classes that extend some other class: {slccdui}%"
        print "(SLCIDUI) Proportion of SL classes that implement some other interface: {slcidui}%"
@@ -777,30 +906,44 @@ do
        print "(SLCCIF) Proportion of SL classes extended by class: {slccif}%"
        print "(SLICIF) Proportion of SL interfaces implemented by class: {slicif}%"
        print "(SLIIIF) Proportion of SL interfaces extended by interface: {sliiif}%"
-       print "--- (SL*SL) Std-Lib Inheritance metrics ---"
+       print ""
+       print "--- (SL -> SL) Std-Lib Inheritance metrics ---"
        print "(SLIFSL) Proportion of SL types Inherited From by SL type: {slinhfsl}%"
        print "(SLCCIFSL) Proportion of SL classes extended by SL class: {slccifsl}%"
        print "(SLICIFSL) Proportion of SL interfaces implemented by SL class: {slicifsl}%"
        print "(SLIIIFSL) Proportion of SL interfaces extended by SL interface: {sliiifsl}%"
-       print "--- (SL*UD) Std-Lib Inheritance metrics ---"
+       print ""
+       print "--- (SL->UD) Std-Lib Inheritance metrics ---"
        print "(SLIFUD) Proportion of SL types Inherited From by UD type: {slinhfud}%"
        print "(SLCCIFUD) Proportion of SL classes extended by UD class: {slccifud}%"
        print "(SLICIFUD) Proportion of SL interfaces implemented by UD class: {slicifud}%"
        print "(SLIIIFUD) Proportion of SL interfaces extended by UD interface: {sliiifud}%"
-       print "--- (UD) User-Defined Inheritance metrics ---"
+       print ""
+       print "--- (UD->*) User-Defined Inheritance metrics ---"
        print "(UDDUI) Proportion of UD types inheriting another type other than Object: {uddui}%"
        print "(UDCCDUI) Proportion of UD classes that extend some other class: {udccdui}%"
        print "(UDCIDUI) Proportion of UD classes that implement some other interface: {udcidui}%"
        print "(UDIIDUI) Proportion of UD interfaces that extend some other interface: {udiidui}%"
        print "(UDIF) Proportion of UD types Inherited From: {udinhf}%"
-       print "(UDCCIF) Proportion of UD classes extended by UD class: {udccif}%"
-       print "(UDICIF) Proportion of UD interfaces implemented by UD class: {udicif}%"
-       print "(UDIIIF) Proportion of UD interfaces extended by UD interface: {udiiif}%"
-       print "--- (UD*UD) User-Defined Inheritance metrics ---"
+       print "(UDCCIF) Proportion of UD classes extended by class: {udccif}%"
+       print "(UDICIF) Proportion of UD interfaces implemented by class: {udicif}%"
+       print "(UDIIIF) Proportion of UD interfaces extended by interface: {udiiif}%"
+       print ""
+       print "--- (UD -> SL) User-Defined Inheritance metrics ---"
+       print "(UDDUISL) Proportion of UD types inheriting another type other SL type: {udduisl}%"
+       print "(UDCCDUISL) Proportion of UD classes that extend some other SL class: {udccduisl}%"
+       print "(UDCIDUISL) Proportion of UD classes that implement some other SL interface: {udciduisl}%"
+       print "(UDIIDUISL) Proportion of UD interfaces that extend some other SL interface: {udiiduisl}%"
+       print ""
+       print "--- (UD -> UD) User-Defined Inheritance metrics ---"
        print "(UDDUIUD) Proportion of UD types inheriting another type other UD type: {udduiud}%"
        print "(UDCCDUIUD) Proportion of UD classes that extend some other UD class: {udccduiud}%"
        print "(UDCIDUIUD) Proportion of UD classes that implement some other UD interface: {udciduiud}%"
        print "(UDIIDUIUD) Proportion of UD interfaces that extend some other UD interface: {udiiduiud}%"
+       print "(UDIFUD) Proportion of UD types Inherited From: {udinhfud}%"
+       print "(UDCCIFUD) Proportion of UD classes extended by UD class: {udccifud}%"
+       print "(UDICIFUD) Proportion of UD interfaces implemented by UD class: {udicifud}%"
+       print "(UDIIIFUD) Proportion of UD interfaces extended by UD interface: {udiiifud}%"
 end
 
 # TODO Third-Party metrics
index 71db364..86d4953 100644 (file)
@@ -38,6 +38,8 @@ redef class ToolContext
        var opt_tables = new OptionBool("Compute tables metrics", "--tables")
        # --rta
        var opt_rta = new OptionBool("Compute RTA metrics", "--rta")
+       # --generate-csv
+       var opt_generate_csv = new OptionBool("Generate CVS format metrics", "--generate-csv")
        # --generate_hyperdoc
        var opt_generate_hyperdoc = new OptionBool("Generate Hyperdoc", "--generate_hyperdoc")
 
@@ -55,6 +57,7 @@ redef class ToolContext
                self.option_context.add_option(opt_static_types)
                self.option_context.add_option(opt_tables)
                self.option_context.add_option(opt_rta)
+               self.option_context.add_option(opt_generate_csv)
                self.option_context.add_option(opt_generate_hyperdoc)
                self.option_context.add_option(opt_dir)
        end
@@ -111,6 +114,42 @@ private class CounterSorter[E: Object]
        redef fun compare(a,b) do return self.counter.map[a] <=> self.counter.map[b]
 end
 
+# Helper class to output metrics as CVS formatted files
+class CSVDocument
+       private var file: String
+       private var header: Array[String] = new Array[String]
+       private var lines: Array[Array[String]] = new Array[Array[String]]
+
+       init(file: String) do self.file = file
+
+       fun set_header(values: Object...) do
+               header.clear
+               for value in values do header.add(value.to_s)
+       end
+
+       fun add_line(values: Object...) do
+               if values.length != header.length then
+                       print "CSV error: header declares {header.length} columns, line contains {values.length} values"
+                       abort
+               end
+               var line = new Array[String]
+               for value in values do line.add(value.to_s)
+               lines.add(line)
+       end
+
+       redef fun to_s do
+               var str = header.join(";") + "\n"
+               for line in lines do str += line.join(";") + "\n"
+               return str
+       end
+
+       fun save do
+               var out = new OFStream.open(self.file)
+               out.write(self.to_s)
+               out.close
+       end
+end
+
 # Helper function to display n/d and handle division by 0
 fun div(n: Int, d: Int): String
 do
index c2f65f5..561d84c 100644 (file)
@@ -61,7 +61,7 @@ var all = toolcontext.opt_all.value
 # Inheritance usage metrics
 if all or toolcontext.opt_inheritance.value then
        print ""
-       compute_inheritance_metrics(model)
+       compute_inheritance_metrics(toolcontext, model)
 end
 
 # Refinement usage metrics