1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Collect common metrics about modules
18 module mmodules_metrics
21 import model
::model_collect
23 redef class ToolContext
25 # MModules related metrics phase
26 var mmodules_metrics_phase
: Phase = new MModulesMetricsPhase(self, null)
29 # Extract metrics about modules from the model.
30 private class MModulesMetricsPhase
32 redef fun process_mainmodule
(mainmodule
, given_mmodules
)
34 if not toolcontext
.opt_mmodules
.value
and not toolcontext
.opt_all
.value
then return
35 var csv
= toolcontext
.opt_csv
.value
36 var out
= "{toolcontext.opt_dir.value or else "metrics"}/mmodules"
39 var model
= toolcontext
.modelbuilder
.model
41 print toolcontext
.format_h1
("\n# MModules metrics")
43 var metrics
= new MetricSet
44 metrics
.register
(new MNOA(model
, mainmodule
))
45 metrics
.register
(new MNOP(model
, mainmodule
))
46 metrics
.register
(new MNOC(model
, mainmodule
))
47 metrics
.register
(new MNOD(model
, mainmodule
))
48 metrics
.register
(new MDIT(model
, mainmodule
))
49 metrics
.register
(new MNBI(model
, mainmodule
))
50 metrics
.register
(new MNBR(model
, mainmodule
))
51 metrics
.register
(new MNBCC(model
, mainmodule
))
52 metrics
.register
(new MNBAC(model
, mainmodule
))
53 metrics
.register
(new MNBIC(model
, mainmodule
))
55 var mmodules
= new HashSet[MModule]
56 for mpackage
in model
.mpackages
do
58 print toolcontext
.format_h2
("\n ## package {mpackage}")
59 for mgroup
in mpackage
.mgroups
do
60 if mgroup
.mmodules
.is_empty
then continue
63 print toolcontext
.format_h3
(" `- group {mgroup.full_name}")
64 mmodules
.add_all
(mgroup
.mmodules
)
66 metrics
.collect
(new HashSet[MModule].from
(mgroup
.mmodules
))
67 metrics
.to_console
(1, not toolcontext
.opt_nocolors
.value
)
68 if csv
then metrics
.to_csv
.write_to_file
("{out}/{mgroup}.csv")
71 if not mmodules
.is_empty
then
73 print toolcontext
.format_h2
("\n ## global metrics")
75 metrics
.collect
(mmodules
)
76 metrics
.to_console
(1, not toolcontext
.opt_nocolors
.value
)
77 if csv
then metrics
.to_csv
.write_to_file
("{out}/summary.csv")
82 # A metric about MModule
83 abstract class MModuleMetric
85 redef type ELM: MModule
87 # Model view used to collect and filter entities
90 # Mainmodule used for linearization
91 var mainmodule
: MModule
93 # Filter to apply on model if any
94 var filter
: nullable ModelFilter
97 # Module Metric: Number of Ancestors
101 redef fun name
do return "mnoa"
102 redef fun desc
do return "number of ancestor modules"
104 redef fun collect
(mmodules
) do
105 for mmodule
in mmodules
do
106 values
[mmodule
] = mmodule
.in_importation
.greaters
.length
- 1
111 # Module Metric: Number of Parents
115 redef fun name
do return "mnop"
116 redef fun desc
do return "number of parent modules"
118 redef fun collect
(mmodules
) do
119 for mmodule
in mmodules
do
120 values
[mmodule
] = mmodule
.in_importation
.direct_greaters
.length
125 # Module Metric: Number of Children
129 redef fun name
do return "mnoc"
130 redef fun desc
do return "number of child modules"
132 redef fun collect
(mmodules
) do
133 for mmodule
in mmodules
do
134 values
[mmodule
] = mmodule
.in_importation
.direct_smallers
.length
139 # Module Metric: Number of Descendants
143 redef fun name
do return "mnod"
144 redef fun desc
do return "number of descendant modules"
146 redef fun collect
(mmodules
) do
147 for mmodule
in mmodules
do
148 values
[mmodule
] = mmodule
.in_importation
.smallers
.length
- 1
153 # Module Metric: Depth in Tree
157 redef fun name
do return "mdit"
158 redef fun desc
do return "depth in module tree"
160 redef fun collect
(mmodules
) do
161 for mmodule
in mmodules
do
162 values
[mmodule
] = mmodule
.in_importation
.depth
167 # Module Metric: Number of Accessible Definitions (of all kind)
169 # count all mclasses accessible by the module
173 redef fun name
do return "mnbd"
174 redef fun desc
do return "number of definition accessibles in module"
176 redef fun collect
(mmodules
) do
177 for mmodule
in mmodules
do
179 for a
in mmodule
.collect_ancestors
(mainmodule
, filter
) do
180 values
[mmodule
] += a
.intro_mclasses
.length
186 # Module Metric: Number of Introduction (of all kind)
188 # count all mclasses introduced by the module
192 redef fun name
do return "mnbi"
193 redef fun desc
do return "number of introduction in module"
195 redef fun collect
(mmodules
) do
196 for mmodule
in mmodules
do
197 values
[mmodule
] = mmodule
.intro_mclasses
.length
202 # Module Metric: Number of Refinement
204 # count all mclasses refined in the module
208 redef fun name
do return "mnbr"
209 redef fun desc
do return "number of refinement in module"
211 redef fun collect
(mmodules
) do
212 for mmodule
in mmodules
do
214 for mclassdef
in mmodule
.mclassdefs
do
215 if not mclassdef
.is_intro
then value
+= 1
217 values
[mmodule
] = value
222 # Module Metric: Number of Concrete Class in module (intro + redef)
226 redef fun name
do return "mnbcc"
227 redef fun desc
do return "number of concrete class in module (intro + redef)"
229 redef fun collect
(mmodules
) do
230 for mmodule
in mmodules
do
232 for mclassdef
in mmodule
.mclassdefs
do
233 if mclassdef
.mclass
.kind
== concrete_kind
then value
+= 1
235 values
[mmodule
] = value
240 # Module Metric: Number of Abstract Class in module (intro + redef)
244 redef fun name
do return "mnbac"
245 redef fun desc
do return "number of abstract class in module (intro + redef)"
247 redef fun collect
(mmodules
) do
248 for mmodule
in mmodules
do
250 for mclassdef
in mmodule
.mclassdefs
do
251 if mclassdef
.mclass
.kind
== abstract_kind
then value
+= 1
253 values
[mmodule
] = value
258 # Module Metric: Number of Interface in module (intro + redef)
262 redef fun name
do return "mnbic"
263 redef fun desc
do return "number of interface in module (intro + redef)"
265 redef fun collect
(mmodules
) do
266 for mmodule
in mmodules
do
268 for mclassdef
in mmodule
.mclassdefs
do
269 if mclassdef
.mclass
.kind
== interface_kind
then value
+= 1
271 values
[mmodule
] = value
276 # Module Metric: Number of Enum in module (intro + redef)
280 redef fun name
do return "mnbec"
281 redef fun desc
do return "number of enum in module (intro + redef)"
283 redef fun collect
(mmodules
) do
284 for mmodule
in mmodules
do
286 for mclassdef
in mmodule
.mclassdefs
do
287 if mclassdef
.mclass
.kind
== enum_kind
then value
+= 1
289 values
[mmodule
] = value