Callref expressions support for Global Compiler
[nit.git] / src / metrics / mclasses_metrics.nit
index 3651aa7..2404a38 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)
+
+       # MClass related metrics phase
+       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
-
-               print "\n# MClasses metrics".yellow.bold
-
-               var metrics = new MClassMetricSet
-               metrics.register(new CNOA, new CNOP, new CNOC, new CNOD, new CDIT)
-               metrics.register(new CNBIP, new CNBRP, new CNBHP)
-               #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 csv = toolcontext.opt_csv.value
+               var out = "{toolcontext.opt_dir.value or else "metrics"}/mclasses"
+               out.mkdir
 
                var model = toolcontext.modelbuilder.model
 
                var model = toolcontext.modelbuilder.model
+               var filter = new ModelFilter(private_visibility)
+
+               print toolcontext.format_h1("\n# MClasses metrics")
+
+               var metrics = new MetricSet
+               metrics.register(new CNOA(model, mainmodule, filter))
+               metrics.register(new CNOP(model, mainmodule, filter))
+               metrics.register(new CNOC(model, mainmodule, filter))
+               metrics.register(new CNOD(model, mainmodule, filter))
+               metrics.register(new CDIT(model, mainmodule, filter))
+               metrics.register(new CNBP(model, mainmodule, filter))
+               metrics.register(new CNBA(model, mainmodule, filter))
+               metrics.register(new CNBI(model, mainmodule, filter))
+               metrics.register(new CNBM(model, mainmodule, filter))
+               metrics.register(new CNBV(model, mainmodule, filter))
+               metrics.register(new CNBIP(model, mainmodule, filter))
+               metrics.register(new CNBRP(model, mainmodule, filter))
+               metrics.register(new CNBHP(model, mainmodule, filter))
+
                var mclasses = new HashSet[MClass]
                var mclasses = new HashSet[MClass]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
 
-                       print "\n ## project {mproject}".bold
+                       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
 
                                # Scalar metrics
-                               print "  `- group {mgroup.full_name}"
-
+                               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
-                                       print "\t{name}: {metric.desc}".green
-                                       print "\t    avg: {metric.avg}".light_gray
-                                       var max = metric.max
-                                       print "\t    max: {max.first} ({max.second})".light_gray
-                                       var min = metric.min
-                                       print "\t    min: {min.first} ({min.second})".light_gray
-                               end
+                               metrics.collect(new HashSet[MClass].from(mod_mclasses))
+                               metrics.to_console(1, not toolcontext.opt_nocolors.value)
+                               if csv then metrics.to_csv.write_to_file("{out}/{mgroup}.csv")
                        end
                end
                if not mclasses.is_empty then
                        end
                end
                if not mclasses.is_empty then
+                       metrics.clear
                        # Global metrics
                        # Global metrics
-                       print "\n ## global metrics".bold
-
-                       metrics.collect(mclasses, mainmodule)
-                       for name, metric in metrics.metrics do
-                               print "\t{name}: {metric.desc}".green
-                               print "\t    avg: {metric.avg}".light_gray
-                               var max = metric.max
-                               print "\t    max: {max.first} ({max.second})".light_gray
-                               var min = metric.min
-                               print "\t    min: {min.first} ({min.second})".light_gray
-                       end
+                       print toolcontext.format_h2("\n ## global metrics")
+                       metrics.collect(mclasses)
+                       metrics.to_console(1, not toolcontext.opt_nocolors.value)
+                       if csv then metrics.to_csv.write_to_file("{out}/summary.csv")
                end
        end
 end
 
                end
        end
 end
 
-# An MetricSet for MClasses metrics
-class MClassMetricSet
-       super MetricSet
-       redef type METRIC: MClassMetric
+# A metric about MClass
+abstract class MClassMetric
+       super Metric
+       redef type ELM: MClass
 
 
-       # 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
-               end
-       end
-end
+       # Model used to collect and filter entities
+       var model: Model
 
 
-# An abstract metric about MClass
-abstract class MClassMetric
-       super IntMetric[MClass]
-       # Collect the metric value for this mclass
-       fun collect(mclass: MClass, mainmodule: MModule) is abstract
+       # Mainmodule for class linearization
+       var mainmodule: MModule
+
+       # Filter to apply
+       var filter: nullable ModelFilter
 end
 
 # Class Metric: Number of Ancestors
 class CNOA
        super MClassMetric
 end
 
 # Class Metric: Number of Ancestors
 class CNOA
        super MClassMetric
+       super IntMetric
        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
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).greaters.length - 1
+               end
        end
 end
 
 # Class Metric: Number of Parents
 class CNOP
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Parents
 class CNOP
        super MClassMetric
+       super IntMetric
        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
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).direct_greaters.length
+               end
        end
 end
 
 # Class Metric: Number of Children
 class CNOC
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Children
 class CNOC
        super MClassMetric
+       super IntMetric
        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
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).direct_smallers.length
+               end
        end
 end
 
 # Class Metric: Number of Descendants
 class CNOD
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Descendants
 class CNOD
        super MClassMetric
+       super IntMetric
        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
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.in_hierarchy(mainmodule).smallers.length - 1
+               end
        end
 end
 
 # Class Metric: Depth in Inheritance Tree
 class CDIT
        super MClassMetric
        end
 end
 
 # Class Metric: Depth in Inheritance Tree
 class CDIT
        super MClassMetric
+       super IntMetric
        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
+       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)"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_mproperties(mainmodule, filter).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)"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_mattributes(mainmodule, filter).length
+               end
+       end
+end
+
+# Class Metric: Number of MMethods
+class CNBM
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnbm"
+       redef fun desc do return "number of accessible methods (inherited + local)"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_mmethods(mainmodule, filter).length
+               end
+       end
+end
+
+# Class Metric: Number of Constructors
+class CNBI
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnbi"
+       redef fun desc do return "number of accessible constructors (inherited + local)"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_inits(mainmodule, filter).length
+               end
+       end
+end
+
+# Class Metric: Number of Virtual Types
+class CNBV
+       super MClassMetric
+       super IntMetric
+       redef fun name do return "cnbv"
+       redef fun desc do return "number of accessible virtual types (inherited + local)"
+
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_accessible_vts(mainmodule, filter).length
+               end
        end
 end
 
 # Class Metric: Number of Introduced MProperties
 class CNBIP
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Introduced MProperties
 class CNBIP
        super MClassMetric
+       super IntMetric
        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"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.intro_mproperties.length
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_intro_mproperties(filter).length
+               end
        end
 end
 
 # Class Metric: Number of Refined MProperties
 class CNBRP
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Refined MProperties
 class CNBRP
        super MClassMetric
+       super IntMetric
        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"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.redef_mproperties.length
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_redef_mproperties(filter).length
+               end
        end
 end
 
 # Class Metric: Number of Inherited MProperties
 class CNBHP
        super MClassMetric
        end
 end
 
 # Class Metric: Number of Inherited MProperties
 class CNBHP
        super MClassMetric
+       super IntMetric
        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"
 
-       redef fun collect(mclass, mainmodule) do
-               values[mclass] = mclass.inherited_mproperties2(mainmodule).length
-       end
-end
-
-redef class MClass
-       # FIXME wait for cleaning in model_utils
-       redef fun intro_mproperties: Set[MProperty] do
-               var set = new HashSet[MProperty]
-               for mclassdef in mclassdefs do
-                       set.add_all(mclassdef.intro_mproperties)
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_inherited_mproperties(mainmodule, filter).length
                end
                end
-               return set
        end
        end
+end
 
 
-       # FIXME wait for cleaning in model_utils
-       redef fun redef_mproperties: Set[MProperty] do
-               var set = new HashSet[MProperty]
-               for mclassdef in mclassdefs do
-                       for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef.mproperty.intro_mclassdef.mclass != self then set.add(mpropdef.mproperty)
-                       end
-               end
-               return set
-       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)"
 
 
-       # FIXME wait for cleaning in model_utils
-       fun inherited_mproperties2(mainmodule: MModule): Set[MProperty] do
-               var set = new HashSet[MProperty]
-               for parent in in_hierarchy(mainmodule).direct_greaters do
-                       set.add_all(parent.intro_mproperties)
-                       set.add_all(parent.inherited_mproperties2(mainmodule))
+       redef fun collect(mclasses) do
+               for mclass in mclasses do
+                       values[mclass] = mclass.collect_local_mproperties(filter).length
                end
                end
-               return set
        end
 end
        end
 end