nitcc: tests script return non-zero on failure (print is not enough)
[nit.git] / src / metrics / inheritance_metrics.nit
index 56ae196..527ece8 100644 (file)
 # Collect metrics about inheritance usage
 module inheritance_metrics
 
 # Collect metrics about inheritance usage
 module inheritance_metrics
 
-import model
+import metrics_base
 import mmodules_metrics
 import mclasses_metrics
 import mmodules_metrics
 import mclasses_metrics
-import phase
-import frontend
 
 redef class ToolContext
 
 redef class ToolContext
-       var inheritance_metrics_phase = new InheritanceMetricsPhase(self, null)
+
+       # Inheritance related metrics phase
+       var inheritance_metrics_phase: Phase = new InheritanceMetricsPhase(self, null)
 end
 
 # Extract metrics about inheritance from model.
 private class InheritanceMetricsPhase
        super Phase
 end
 
 # Extract metrics about inheritance from model.
 private class InheritanceMetricsPhase
        super Phase
-       redef fun process_mainmodule(mainmodule)
+       redef fun process_mainmodule(mainmodule, given_mmodules)
        do
                if not toolcontext.opt_inheritance.value and not toolcontext.opt_all.value then return
        do
                if not toolcontext.opt_inheritance.value and not toolcontext.opt_all.value then return
+               var csv = toolcontext.opt_csv.value
+               var out = "{toolcontext.opt_dir.value or else "metrics"}/inheritance"
+               out.mkdir
+
+               var model = toolcontext.modelbuilder.model
+               var filter = new ModelFilter(min_visibility = private_visibility)
 
                print toolcontext.format_h1("\n# Inheritance metrics")
 
 
                print toolcontext.format_h1("\n# Inheritance metrics")
 
-               var hmetrics = new InheritanceMetricSet
-               hmetrics.register(new MDUI(mainmodule))
-               hmetrics.register(new MDUIC(mainmodule))
-               hmetrics.register(new MDUII(mainmodule))
-               hmetrics.register(new MIF(mainmodule))
-               hmetrics.register(new MIFC(mainmodule))
-               hmetrics.register(new MIFI(mainmodule))
-
-               var cmetrics = new MClassMetricSet
-               cmetrics.register(new CNOAC(mainmodule))
-               cmetrics.register(new CNOPC(mainmodule))
-               cmetrics.register(new CNOCC(mainmodule))
-               cmetrics.register(new CNODC(mainmodule))
-               cmetrics.register(new CNOPI(mainmodule))
-               cmetrics.register(new CNOCI(mainmodule))
-               cmetrics.register(new CNODI(mainmodule))
-               cmetrics.register(new CDITC(mainmodule))
-               cmetrics.register(new CDITI(mainmodule))
+               var hmetrics = new MetricSet
+               hmetrics.register(new MDUI(model, mainmodule))
+               hmetrics.register(new MDUIC(model, mainmodule))
+               hmetrics.register(new MDUII(model, mainmodule))
+               hmetrics.register(new MIF(model, mainmodule))
+               hmetrics.register(new MIFC(model, mainmodule))
+               hmetrics.register(new MIFI(model, mainmodule))
+
+               var cmetrics = new MetricSet
+               cmetrics.register(new CNOAC(model, mainmodule, filter))
+               cmetrics.register(new CNOPC(model, mainmodule, filter))
+               cmetrics.register(new CNOCC(model, mainmodule, filter))
+               cmetrics.register(new CNODC(model, mainmodule, filter))
+               cmetrics.register(new CNOPI(model, mainmodule, filter))
+               cmetrics.register(new CNOCI(model, mainmodule, filter))
+               cmetrics.register(new CNODI(model, mainmodule, filter))
+               cmetrics.register(new CDITC(model, mainmodule, filter))
+               cmetrics.register(new CDITI(model, mainmodule, filter))
 
 
-               var model = toolcontext.modelbuilder.model
                var mmodules = new HashSet[MModule]
                var mclasses = new HashSet[MClass]
                var mmodules = new HashSet[MModule]
                var mclasses = new HashSet[MClass]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
 
-                       print toolcontext.format_h2("\n ## project {mproject}")
+                       print toolcontext.format_h2("\n ## package {mpackage}")
 
 
-                       for mgroup in mproject.mgroups do
+                       for mgroup in mpackage.mgroups do
                                if mgroup.mmodules.is_empty then continue
 
                                # Scalar metrics
                                if mgroup.mmodules.is_empty then continue
 
                                # Scalar metrics
@@ -73,67 +78,27 @@ private class InheritanceMetricsPhase
                                if mod_mclasses.is_empty then continue
                                mmodules.add_all(mgroup.mmodules)
                                mclasses.add_all(mod_mclasses)
                                if mod_mclasses.is_empty then continue
                                mmodules.add_all(mgroup.mmodules)
                                mclasses.add_all(mod_mclasses)
-                               cmetrics.collect(new HashSet[MClass].from(mod_mclasses), mainmodule)
-                               for name, metric in cmetrics.metrics do
-                                       if metric isa IntMetric then
-                                               print toolcontext.format_h4("\t{name}: {metric.desc}")
-                                               print toolcontext.format_p("\t    avg: {metric.avg}")
-                                               var max = metric.max
-                                               print toolcontext.format_p("\t    max: {max.first} ({max.second})")
-                                               var min = metric.min
-                                               print toolcontext.format_p("\t    min: {min.first} ({min.second})")
-                                       end
-                               end
-                               hmetrics.collect(new HashSet[MModule].from(mgroup.mmodules), mainmodule)
-                               for name, metric in hmetrics.metrics do
-                                       if metric isa FloatMetric then
-                                               print toolcontext.format_h4("\t{name}: {metric.desc}")
-                                               print toolcontext.format_p("\t    avg: {metric.avg}")
-                                               var max = metric.max
-                                               print toolcontext.format_p("\t    max: {max.first} ({max.second})")
-                                               var min = metric.min
-                                               print toolcontext.format_p("\t    min: {min.first} ({min.second})")
-                                       end
-                               end
+                               cmetrics.clear
+                               cmetrics.collect(new HashSet[MClass].from(mod_mclasses))
+                               cmetrics.to_console(1, not toolcontext.opt_nocolors.value)
+                               if csv then cmetrics.to_csv.write_to_file("{out}/{mgroup}_classes.csv")
+                               hmetrics.clear
+                               hmetrics.collect(new HashSet[MModule].from(mgroup.mmodules))
+                               hmetrics.to_console(1, not toolcontext.opt_nocolors.value)
+                               if csv then hmetrics.to_csv.write_to_file("{out}/{mgroup}_inheritance.csv")
                        end
                end
                if not mclasses.is_empty then
                        # Global metrics
                        print toolcontext.format_h2("\n ## global metrics")
                        end
                end
                if not mclasses.is_empty then
                        # Global metrics
                        print toolcontext.format_h2("\n ## global metrics")
-                       cmetrics.collect(mclasses, mainmodule)
-                       for name, metric in cmetrics.metrics do
-                               if metric isa IntMetric then
-                                       print toolcontext.format_h4("\t{name}: {metric.desc}")
-                                       print toolcontext.format_p("\t    avg: {metric.avg}")
-                                       var max = metric.max
-                                       print toolcontext.format_p("\t    max: {max.first} ({max.second})")
-                                       var min = metric.min
-                                       print toolcontext.format_p("\t    min: {min.first} ({min.second})")
-                               end
-                       end
-                       hmetrics.collect(mmodules, mainmodule)
-                       for name, metric in hmetrics.metrics do
-                               if metric isa FloatMetric then
-                                       print toolcontext.format_h4("\t{name}: {metric.desc}")
-                                       print toolcontext.format_p("\t    avg: {metric.avg}")
-                                       var max = metric.max
-                                       print toolcontext.format_p("\t    max: {max.first} ({max.second})")
-                                       var min = metric.min
-                                       print toolcontext.format_p("\t    min: {min.first} ({min.second})")
-                               end
-                       end
-               end
-       end
-end
-
-# Metric Set used to collect data about inheritance in each module
-class InheritanceMetricSet
-       super MetricSet
-       redef type METRIC: MModuleMetric
-       fun collect(mmodules: Set[MModule], mainmodule: MModule) do
-               clear
-               for metric in metrics.values do
-                       metric.collect(mmodules)
+                       cmetrics.clear
+                       cmetrics.collect(mclasses)
+                       cmetrics.to_console(1, not toolcontext.opt_nocolors.value)
+                       if csv then cmetrics.to_csv.write_to_file("{out}/summary_classes.csv")
+                       hmetrics.clear
+                       hmetrics.collect(mmodules)
+                       hmetrics.to_console(1, not toolcontext.opt_nocolors.value)
+                       if csv then hmetrics.to_csv.write_to_file("{out}/summary_inheritance.csv")
                end
        end
 end
                end
        end
 end
@@ -147,9 +112,6 @@ class MDUI
        redef fun name do return "mdui"
        redef fun desc do return "proportion of mclass defined using inheritance (has other parent than Object)"
 
        redef fun name do return "mdui"
        redef fun desc do return "proportion of mclass defined using inheritance (has other parent than Object)"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -174,9 +136,6 @@ class MDUIC
        redef fun name do return "mduic"
        redef fun desc do return "proportion of class_kind defined using inheritance"
 
        redef fun name do return "mduic"
        redef fun desc do return "proportion of class_kind defined using inheritance"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -205,9 +164,6 @@ class MDUII
        redef fun name do return "mduii"
        redef fun desc do return "proportion of interface_kind defined using inheritance"
 
        redef fun name do return "mduii"
        redef fun desc do return "proportion of interface_kind defined using inheritance"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -236,9 +192,6 @@ class MIF
        redef fun name do return "mif"
        redef fun desc do return "proportion of mclass inherited from"
 
        redef fun name do return "mif"
        redef fun desc do return "proportion of mclass inherited from"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -263,9 +216,6 @@ class MIFC
        redef fun name do return "mifc"
        redef fun desc do return "proportion of class_kind inherited from"
 
        redef fun name do return "mifc"
        redef fun desc do return "proportion of class_kind inherited from"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -294,9 +244,6 @@ class MIFI
        redef fun name do return "mifi"
        redef fun desc do return "proportion of interface_kind inherited from"
 
        redef fun name do return "mifi"
        redef fun desc do return "proportion of interface_kind inherited from"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
        redef fun collect(mmodules) do
                for mmodule in mmodules do
                        var count = 0
@@ -325,9 +272,6 @@ class CNOAC
        redef fun name do return "cnoac"
        redef fun desc do return "number of class_kind ancestor"
 
        redef fun name do return "cnoac"
        redef fun desc do return "number of class_kind ancestor"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -351,9 +295,6 @@ class CNOPC
        redef fun name do return "cnopc"
        redef fun desc do return "number of class_kind parent"
 
        redef fun name do return "cnopc"
        redef fun desc do return "number of class_kind parent"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -377,9 +318,6 @@ class CNOCC
        redef fun name do return "cnocc"
        redef fun desc do return "number of class_kind children"
 
        redef fun name do return "cnocc"
        redef fun desc do return "number of class_kind children"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -403,9 +341,6 @@ class CNODC
        redef fun name do return "cnodc"
        redef fun desc do return "number of class_kind descendants"
 
        redef fun name do return "cnodc"
        redef fun desc do return "number of class_kind descendants"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -420,6 +355,29 @@ class CNODC
        end
 end
 
        end
 end
 
+# MClass metric: Number of Abstract Class Ancestors
+#
+# Count only absrtract classes
+class CNOAA
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnoaa"
+       redef fun desc do return "number of abstract class ancestors"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       var count = 0
+                       for parent in mclass.in_hierarchy(mainmodule).greaters do
+                               if parent == mclass then continue
+                               if parent.kind == abstract_kind then
+                                       count += 1
+                               end
+                       end
+                       values[mclass] = count
+               end
+       end
+end
+
 # MClass metric: Number of Interface Ancestors
 #
 # Count only interfaces
 # MClass metric: Number of Interface Ancestors
 #
 # Count only interfaces
@@ -429,9 +387,6 @@ class CNOAI
        redef fun name do return "cnoai"
        redef fun desc do return "number of interface_kind ancestor"
 
        redef fun name do return "cnoai"
        redef fun desc do return "number of interface_kind ancestor"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -455,9 +410,6 @@ class CNOPI
        redef fun name do return "cnopi"
        redef fun desc do return "number of interface_kind parent"
 
        redef fun name do return "cnopi"
        redef fun desc do return "number of interface_kind parent"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -481,9 +433,6 @@ class CNOCI
        redef fun name do return "cnoci"
        redef fun desc do return "number of interface_kind children"
 
        redef fun name do return "cnoci"
        redef fun desc do return "number of interface_kind children"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -507,9 +456,6 @@ class CNODI
        redef fun name do return "cnodi"
        redef fun desc do return "number of interface_kind descendants"
 
        redef fun name do return "cnodi"
        redef fun desc do return "number of interface_kind descendants"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        var count = 0
@@ -533,9 +479,6 @@ class CDITC
        redef fun name do return "cditc"
        redef fun desc do return "depth in class tree following only class, abstract, extern kind"
 
        redef fun name do return "cditc"
        redef fun desc do return "depth in class tree following only class, abstract, extern kind"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        values[mclass] = mclass.ditc(mainmodule)
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        values[mclass] = mclass.ditc(mainmodule)
@@ -552,9 +495,6 @@ class CDITI
        redef fun name do return "cditi"
        redef fun desc do return "depth in class tree following only interface_kind"
 
        redef fun name do return "cditi"
        redef fun desc do return "depth in class tree following only interface_kind"
 
-       var mainmodule: MModule
-       init(mainmodule: MModule) do self.mainmodule = mainmodule
-
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        values[mclass] = mclass.diti(mainmodule)
        redef fun collect(mclasses) do
                for mclass in mclasses do
                        values[mclass] = mclass.diti(mainmodule)
@@ -565,7 +505,7 @@ end
 # model redef
 
 redef class MClass
 # model redef
 
 redef class MClass
-               
+
        # Class Depth in Inheritance Tree
        #
        # Following the longest path composed only of extends edges from self to Object
        # Class Depth in Inheritance Tree
        #
        # Following the longest path composed only of extends edges from self to Object
@@ -604,4 +544,3 @@ redef class MClass
                return min
        end
 end
                return min
        end
 end
-