model: fix `try_get_primitive_method`
[nit.git] / src / metrics / mclasses_metrics.nit
index 69a1063..69b5b40 100644 (file)
 # Collect common metrics about mclasses
 module mclasses_metrics
 
 # Collect common metrics about mclasses
 module mclasses_metrics
 
-import model
 import metrics_base
 import metrics_base
-import phase
-import frontend
+import model::model_collect
 
 redef class ToolContext
 
 redef class ToolContext
-       var mclasses_metrics_phase = new MClassesMetricsPhase(self, null)
+       var mclasses_metrics_phase: Phase = new MClassesMetricsPhase(self, null)
 end
 
 # Extract metrics about mclasses from model.
 private class MClassesMetricsPhase
        super Phase
 end
 
 # Extract metrics about mclasses from model.
 private class MClassesMetricsPhase
        super Phase
-       redef fun process_mainmodule(mainmodule)
+       redef fun process_mainmodule(mainmodule, given_mmodules)
        do
                if not toolcontext.opt_mclasses.value and not toolcontext.opt_all.value then return
        do
                if not toolcontext.opt_mclasses.value and not toolcontext.opt_all.value then return
+               var csv = toolcontext.opt_csv.value
+               var out = "{toolcontext.opt_dir.value or else "metrics"}/mclasses"
+               out.mkdir
+
 
                print toolcontext.format_h1("\n# MClasses metrics")
 
 
                print toolcontext.format_h1("\n# MClasses metrics")
 
-               var metrics = new MClassMetricSet
+               var metrics = new MetricSet
                var min_vis = private_visibility
                var min_vis = private_visibility
-               metrics.register(new CNOA, new CNOP, new CNOC, new CNOD, new CDIT)
-               metrics.register(new CNBIP(min_vis), new CNBRP(min_vis), new CNBHP(min_vis))
+               metrics.register(new CNOA(mainmodule))
+               metrics.register(new CNOP(mainmodule))
+               metrics.register(new CNOC(mainmodule))
+               metrics.register(new CNOD(mainmodule))
+               metrics.register(new CDIT(mainmodule))
+               metrics.register(new CNBP(mainmodule, min_vis))
+               metrics.register(new CNBA(mainmodule, min_vis))
+               metrics.register(new CNBIP(mainmodule, min_vis))
+               metrics.register(new CNBRP(mainmodule, min_vis))
+               metrics.register(new CNBHP(mainmodule, min_vis))
                #TODO metrics.register(new CNBI) # nb init
                #TODO metrics.register(new CNBI) # nb init
-               #TODO metrics.register(new CNBA) # nb attrs
                #TODO metrics.register(new CNBM) # nb methods
                #TODO metrics.register(new CNBV) # nb vtypes
 
                var model = toolcontext.modelbuilder.model
                var mclasses = new HashSet[MClass]
                #TODO metrics.register(new CNBM) # nb methods
                #TODO metrics.register(new CNBV) # nb vtypes
 
                var model = toolcontext.modelbuilder.model
                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
                                if mgroup.mmodules.is_empty then continue
+                               metrics.clear
 
                                # Scalar metrics
                                print toolcontext.format_h3("  `- group {mgroup.full_name}")
 
                                # Scalar metrics
                                print toolcontext.format_h3("  `- group {mgroup.full_name}")
-
                                var mod_mclasses = new HashSet[MClass]
                                for mmodule in mgroup.mmodules do mod_mclasses.add_all(mmodule.intro_mclasses)
                                if mod_mclasses.is_empty then continue
                                mclasses.add_all(mod_mclasses)
                                var mod_mclasses = new HashSet[MClass]
                                for mmodule in mgroup.mmodules do mod_mclasses.add_all(mmodule.intro_mclasses)
                                if mod_mclasses.is_empty then continue
                                mclasses.add_all(mod_mclasses)
-                               metrics.collect(new HashSet[MClass].from(mod_mclasses), mainmodule)
-                               for name, metric in metrics.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
+                               metrics.collect(new HashSet[MClass].from(mod_mclasses))
+                               metrics.to_console(1, not toolcontext.opt_nocolors.value)
+                               if csv then metrics.to_csv.save("{out}/{mgroup}.csv")
                        end
                end
                if not mclasses.is_empty then
                        end
                end
                if not mclasses.is_empty then
+                       metrics.clear
                        # Global metrics
                        print toolcontext.format_h2("\n ## global metrics")
                        # Global metrics
                        print toolcontext.format_h2("\n ## global metrics")
-
-                       metrics.collect(mclasses, mainmodule)
-                       for name, metric in metrics.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
-               end
-       end
-end
-
-# An MetricSet for MClasses metrics
-class MClassMetricSet
-       super MetricSet
-       redef type METRIC: MClassMetric
-
-       # Collect all the metrics on the set of MClasses
-       fun collect(mclasses: Set[MClass], mainmodule: MModule) do
-               clear
-               for metric in metrics.values do
-                       for mclass in mclasses do
-                               metric.collect(mclass, mainmodule)
-                       end
+                       metrics.collect(mclasses)
+                       metrics.to_console(1, not toolcontext.opt_nocolors.value)
+                       if csv then metrics.to_csv.save("{out}/summary.csv")
                end
        end
 end
                end
        end
 end
@@ -112,9 +89,6 @@ end
 interface MClassMetric
        super Metric
        redef type ELM: MClass
 interface MClassMetric
        super Metric
        redef type ELM: MClass
-
-       # Collect the metric value for this mclass
-       fun collect(mclass: MClass, mainmodule: MModule) is abstract
 end
 
 # Class Metric: Number of Ancestors
 end
 
 # Class Metric: Number of Ancestors
@@ -124,8 +98,13 @@ class CNOA
        redef fun name do return "cnoa"
        redef fun desc do return "number of ancestor classes"
 
        redef fun name do return "cnoa"
        redef fun desc do return "number of ancestor classes"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.in_hierarchy(mainmodule).greaters.length - 1
+       var mainmodule: MModule
+       init(mainmodule: MModule) do self.mainmodule = mainmodule
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).greaters.length - 1
+               end
        end
 end
 
        end
 end
 
@@ -136,8 +115,13 @@ class CNOP
        redef fun name do return "cnop"
        redef fun desc do return "number of parent classes"
 
        redef fun name do return "cnop"
        redef fun desc do return "number of parent classes"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.in_hierarchy(mainmodule).direct_greaters.length
+       var mainmodule: MModule
+       init(mainmodule: MModule) do self.mainmodule = mainmodule
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).direct_greaters.length
+               end
        end
 end
 
        end
 end
 
@@ -148,8 +132,13 @@ class CNOC
        redef fun name do return "cnoc"
        redef fun desc do return "number of child classes"
 
        redef fun name do return "cnoc"
        redef fun desc do return "number of child classes"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.in_hierarchy(mainmodule).direct_smallers.length
+       var mainmodule: MModule
+       init(mainmodule: MModule) do self.mainmodule = mainmodule
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).direct_smallers.length
+               end
        end
 end
 
        end
 end
 
@@ -160,8 +149,13 @@ class CNOD
        redef fun name do return "cnod"
        redef fun desc do return "number of descendant classes"
 
        redef fun name do return "cnod"
        redef fun desc do return "number of descendant classes"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.in_hierarchy(mainmodule).smallers.length - 1
+       var mainmodule: MModule
+       init(mainmodule: MModule) do self.mainmodule = mainmodule
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).smallers.length - 1
+               end
        end
 end
 
        end
 end
 
@@ -172,8 +166,57 @@ class CDIT
        redef fun name do return "cdit"
        redef fun desc do return "depth in class tree"
 
        redef fun name do return "cdit"
        redef fun desc do return "depth in class tree"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.in_hierarchy(mainmodule).depth
+       var mainmodule: MModule
+       init(mainmodule: MModule) do self.mainmodule = mainmodule
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).depth
+               end
+       end
+end
+
+# Class Metric: Number of MProperties
+class CNBP
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnbp"
+       redef fun desc do return "number of accessible properties (inherited + local)"
+
+       var mainmodule: MModule
+       var min_visibility: MVisibility
+
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_mproperties(min_visibility).length
+               end
+       end
+end
+
+# Class Metric: Number of MAttributes
+class CNBA
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnba"
+       redef fun desc do return "number of accessible attributes (inherited + local)"
+
+       var mainmodule: MModule
+       var min_visibility: MVisibility
+
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_mattributes(min_visibility).length
+               end
        end
 end
 
        end
 end
 
@@ -184,11 +227,18 @@ class CNBIP
        redef fun name do return "cnbip"
        redef fun desc do return "number of introduced properties"
 
        redef fun name do return "cnbip"
        redef fun desc do return "number of introduced properties"
 
+       var mainmodule: MModule
        var min_visibility: MVisibility
        var min_visibility: MVisibility
-       init(min_visibility: MVisibility) do self.min_visibility = min_visibility
 
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.intro_mproperties(min_visibility).length
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_intro_mproperties(min_visibility).length
+               end
        end
 end
 
        end
 end
 
@@ -199,11 +249,18 @@ class CNBRP
        redef fun name do return "cnbrp"
        redef fun desc do return "number of redefined properties"
 
        redef fun name do return "cnbrp"
        redef fun desc do return "number of redefined properties"
 
+       var mainmodule: MModule
        var min_visibility: MVisibility
        var min_visibility: MVisibility
-       init(min_visibility: MVisibility) do self.min_visibility = min_visibility
 
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.redef_mproperties(min_visibility).length
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_redef_mproperties(min_visibility).length
+               end
        end
 end
 
        end
 end
 
@@ -214,11 +271,39 @@ class CNBHP
        redef fun name do return "cnbhp"
        redef fun desc do return "number of inherited properties"
 
        redef fun name do return "cnbhp"
        redef fun desc do return "number of inherited properties"
 
+       var mainmodule: MModule
        var min_visibility: MVisibility
        var min_visibility: MVisibility
-       init(min_visibility: MVisibility) do self.min_visibility = min_visibility
 
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.inherited_mproperties(mainmodule, min_visibility).length
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_inherited_mproperties(min_visibility).length
+               end
        end
 end
 
        end
 end
 
+# Class Metric: Number of Local MProperties (Intro + Redef)
+class CNBLP
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnblp"
+       redef fun desc do return "number of local properties (intro + redef)"
+
+       var mainmodule: MModule
+       var min_visibility: MVisibility
+
+       init(mainmodule: MModule, min_visibility: MVisibility) do
+               self.mainmodule = mainmodule
+               self.min_visibility = min_visibility
+       end
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_local_mproperties(min_visibility).length
+               end
+       end
+end