1e9d190a289672b3e6cdcc1abeab913be31362ac
[nit.git] / src / metrics / mmodules_metrics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Collect common metrics about modules
18 module mmodules_metrics
19
20 import metrics_base
21 import model::model_collect
22
23 redef class ToolContext
24
25 # MModules related metrics phase
26 var mmodules_metrics_phase: Phase = new MModulesMetricsPhase(self, null)
27 end
28
29 # Extract metrics about modules from the model.
30 private class MModulesMetricsPhase
31 super Phase
32 redef fun process_mainmodule(mainmodule, given_mmodules)
33 do
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"
37 out.mkdir
38
39 var model = toolcontext.modelbuilder.model
40 var model_view = model.private_view
41
42 print toolcontext.format_h1("\n# MModules metrics")
43
44 var metrics = new MetricSet
45 metrics.register(new MNOA(mainmodule, model_view))
46 metrics.register(new MNOP(mainmodule, model_view))
47 metrics.register(new MNOC(mainmodule, model_view))
48 metrics.register(new MNOD(mainmodule, model_view))
49 metrics.register(new MDIT(mainmodule, model_view))
50 metrics.register(new MNBI(mainmodule, model_view))
51 metrics.register(new MNBR(mainmodule, model_view))
52 metrics.register(new MNBCC(mainmodule, model_view))
53 metrics.register(new MNBAC(mainmodule, model_view))
54 metrics.register(new MNBIC(mainmodule, model_view))
55
56 var mmodules = new HashSet[MModule]
57 for mpackage in model.mpackages do
58
59 print toolcontext.format_h2("\n ## package {mpackage}")
60 for mgroup in mpackage.mgroups do
61 if mgroup.mmodules.is_empty then continue
62
63 # Scalar metrics
64 print toolcontext.format_h3(" `- group {mgroup.full_name}")
65 mmodules.add_all(mgroup.mmodules)
66 metrics.clear
67 metrics.collect(new HashSet[MModule].from(mgroup.mmodules))
68 metrics.to_console(1, not toolcontext.opt_nocolors.value)
69 if csv then metrics.to_csv.write_to_file("{out}/{mgroup}.csv")
70 end
71 end
72 if not mmodules.is_empty then
73 # Global metrics
74 print toolcontext.format_h2("\n ## global metrics")
75 metrics.clear
76 metrics.collect(mmodules)
77 metrics.to_console(1, not toolcontext.opt_nocolors.value)
78 if csv then metrics.to_csv.write_to_file("{out}/summary.csv")
79 end
80 end
81 end
82
83 # A metric about MModule
84 abstract class MModuleMetric
85 super Metric
86 redef type ELM: MModule
87
88 # Main module used for linearization
89 var mainmodule: MModule
90
91 # Model view used to collect and filter entities
92 var model_view: ModelView
93 end
94
95 # Module Metric: Number of Ancestors
96 class MNOA
97 super MModuleMetric
98 super IntMetric
99 redef fun name do return "mnoa"
100 redef fun desc do return "number of ancestor modules"
101
102 redef fun collect(mmodules) do
103 for mmodule in mmodules do
104 values[mmodule] = mmodule.in_importation.greaters.length - 1
105 end
106 end
107 end
108
109 # Module Metric: Number of Parents
110 class MNOP
111 super MModuleMetric
112 super IntMetric
113 redef fun name do return "mnop"
114 redef fun desc do return "number of parent modules"
115
116 redef fun collect(mmodules) do
117 for mmodule in mmodules do
118 values[mmodule] = mmodule.in_importation.direct_greaters.length
119 end
120 end
121 end
122
123 # Module Metric: Number of Children
124 class MNOC
125 super MModuleMetric
126 super IntMetric
127 redef fun name do return "mnoc"
128 redef fun desc do return "number of child modules"
129
130 redef fun collect(mmodules) do
131 for mmodule in mmodules do
132 values[mmodule] = mmodule.in_importation.direct_smallers.length
133 end
134 end
135 end
136
137 # Module Metric: Number of Descendants
138 class MNOD
139 super MModuleMetric
140 super IntMetric
141 redef fun name do return "mnod"
142 redef fun desc do return "number of descendant modules"
143
144 redef fun collect(mmodules) do
145 for mmodule in mmodules do
146 values[mmodule] = mmodule.in_importation.smallers.length - 1
147 end
148 end
149 end
150
151 # Module Metric: Depth in Tree
152 class MDIT
153 super MModuleMetric
154 super IntMetric
155 redef fun name do return "mdit"
156 redef fun desc do return "depth in module tree"
157
158 redef fun collect(mmodules) do
159 for mmodule in mmodules do
160 values[mmodule] = mmodule.in_importation.depth
161 end
162 end
163 end
164
165 # Module Metric: Number of Accessible Definitions (of all kind)
166 #
167 # count all mclasses accessible by the module
168 class MNBD
169 super MModuleMetric
170 super IntMetric
171 redef fun name do return "mnbd"
172 redef fun desc do return "number of definition accessibles in module"
173
174 redef fun collect(mmodules) do
175 for mmodule in mmodules do
176 values[mmodule] = 0
177 for a in mmodule.collect_ancestors(model_view) do
178 values[mmodule] += a.intro_mclasses.length
179 end
180 end
181 end
182 end
183
184 # Module Metric: Number of Introduction (of all kind)
185 #
186 # count all mclasses introduced by the module
187 class MNBI
188 super MModuleMetric
189 super IntMetric
190 redef fun name do return "mnbi"
191 redef fun desc do return "number of introduction in module"
192
193 redef fun collect(mmodules) do
194 for mmodule in mmodules do
195 values[mmodule] = mmodule.intro_mclasses.length
196 end
197 end
198 end
199
200 # Module Metric: Number of Refinement
201 #
202 # count all mclasses refined in the module
203 class MNBR
204 super MModuleMetric
205 super IntMetric
206 redef fun name do return "mnbr"
207 redef fun desc do return "number of refinement in module"
208
209 redef fun collect(mmodules) do
210 for mmodule in mmodules do
211 var value = 0
212 for mclassdef in mmodule.mclassdefs do
213 if not mclassdef.is_intro then value += 1
214 end
215 values[mmodule] = value
216 end
217 end
218 end
219
220 # Module Metric: Number of Concrete Class in module (intro + redef)
221 class MNBCC
222 super MModuleMetric
223 super IntMetric
224 redef fun name do return "mnbcc"
225 redef fun desc do return "number of concrete class in module (intro + redef)"
226
227 redef fun collect(mmodules) do
228 for mmodule in mmodules do
229 var value = 0
230 for mclassdef in mmodule.mclassdefs do
231 if mclassdef.mclass.kind == concrete_kind then value += 1
232 end
233 values[mmodule] = value
234 end
235 end
236 end
237
238 # Module Metric: Number of Abstract Class in module (intro + redef)
239 class MNBAC
240 super MModuleMetric
241 super IntMetric
242 redef fun name do return "mnbac"
243 redef fun desc do return "number of abstract class in module (intro + redef)"
244
245 redef fun collect(mmodules) do
246 for mmodule in mmodules do
247 var value = 0
248 for mclassdef in mmodule.mclassdefs do
249 if mclassdef.mclass.kind == abstract_kind then value += 1
250 end
251 values[mmodule] = value
252 end
253 end
254 end
255
256 # Module Metric: Number of Interface in module (intro + redef)
257 class MNBIC
258 super MModuleMetric
259 super IntMetric
260 redef fun name do return "mnbic"
261 redef fun desc do return "number of interface in module (intro + redef)"
262
263 redef fun collect(mmodules) do
264 for mmodule in mmodules do
265 var value = 0
266 for mclassdef in mmodule.mclassdefs do
267 if mclassdef.mclass.kind == interface_kind then value += 1
268 end
269 values[mmodule] = value
270 end
271 end
272 end
273
274 # Module Metric: Number of Enum in module (intro + redef)
275 class MNBEC
276 super MModuleMetric
277 super IntMetric
278 redef fun name do return "mnbec"
279 redef fun desc do return "number of enum in module (intro + redef)"
280
281 redef fun collect(mmodules) do
282 for mmodule in mmodules do
283 var value = 0
284 for mclassdef in mmodule.mclassdefs do
285 if mclassdef.mclass.kind == enum_kind then value += 1
286 end
287 values[mmodule] = value
288 end
289 end
290 end