Merge: gamnit: new services and a lot of bug fixes and performance improvements
[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 = new ModelView(model, mainmodule)
41
42 print toolcontext.format_h1("\n# MModules metrics")
43
44 var metrics = new MetricSet
45 metrics.register(new MNOA(model_view))
46 metrics.register(new MNOP(model_view))
47 metrics.register(new MNOC(model_view))
48 metrics.register(new MNOD(model_view))
49 metrics.register(new MDIT(model_view))
50 metrics.register(new MNBI(model_view))
51 metrics.register(new MNBR(model_view))
52 metrics.register(new MNBCC(model_view))
53 metrics.register(new MNBAC(model_view))
54 metrics.register(new MNBIC(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 # Model view used to collect and filter entities
89 var model_view: ModelView
90 end
91
92 # Module Metric: Number of Ancestors
93 class MNOA
94 super MModuleMetric
95 super IntMetric
96 redef fun name do return "mnoa"
97 redef fun desc do return "number of ancestor modules"
98
99 redef fun collect(mmodules) do
100 for mmodule in mmodules do
101 values[mmodule] = mmodule.in_importation.greaters.length - 1
102 end
103 end
104 end
105
106 # Module Metric: Number of Parents
107 class MNOP
108 super MModuleMetric
109 super IntMetric
110 redef fun name do return "mnop"
111 redef fun desc do return "number of parent modules"
112
113 redef fun collect(mmodules) do
114 for mmodule in mmodules do
115 values[mmodule] = mmodule.in_importation.direct_greaters.length
116 end
117 end
118 end
119
120 # Module Metric: Number of Children
121 class MNOC
122 super MModuleMetric
123 super IntMetric
124 redef fun name do return "mnoc"
125 redef fun desc do return "number of child modules"
126
127 redef fun collect(mmodules) do
128 for mmodule in mmodules do
129 values[mmodule] = mmodule.in_importation.direct_smallers.length
130 end
131 end
132 end
133
134 # Module Metric: Number of Descendants
135 class MNOD
136 super MModuleMetric
137 super IntMetric
138 redef fun name do return "mnod"
139 redef fun desc do return "number of descendant modules"
140
141 redef fun collect(mmodules) do
142 for mmodule in mmodules do
143 values[mmodule] = mmodule.in_importation.smallers.length - 1
144 end
145 end
146 end
147
148 # Module Metric: Depth in Tree
149 class MDIT
150 super MModuleMetric
151 super IntMetric
152 redef fun name do return "mdit"
153 redef fun desc do return "depth in module tree"
154
155 redef fun collect(mmodules) do
156 for mmodule in mmodules do
157 values[mmodule] = mmodule.in_importation.depth
158 end
159 end
160 end
161
162 # Module Metric: Number of Accessible Definitions (of all kind)
163 #
164 # count all mclasses accessible by the module
165 class MNBD
166 super MModuleMetric
167 super IntMetric
168 redef fun name do return "mnbd"
169 redef fun desc do return "number of definition accessibles in module"
170
171 redef fun collect(mmodules) do
172 for mmodule in mmodules do
173 values[mmodule] = 0
174 for a in mmodule.collect_ancestors(model_view) do
175 values[mmodule] += a.intro_mclasses.length
176 end
177 end
178 end
179 end
180
181 # Module Metric: Number of Introduction (of all kind)
182 #
183 # count all mclasses introduced by the module
184 class MNBI
185 super MModuleMetric
186 super IntMetric
187 redef fun name do return "mnbi"
188 redef fun desc do return "number of introduction in module"
189
190 redef fun collect(mmodules) do
191 for mmodule in mmodules do
192 values[mmodule] = mmodule.intro_mclasses.length
193 end
194 end
195 end
196
197 # Module Metric: Number of Refinement
198 #
199 # count all mclasses refined in the module
200 class MNBR
201 super MModuleMetric
202 super IntMetric
203 redef fun name do return "mnbr"
204 redef fun desc do return "number of refinement in module"
205
206 redef fun collect(mmodules) do
207 for mmodule in mmodules do
208 var value = 0
209 for mclassdef in mmodule.mclassdefs do
210 if not mclassdef.is_intro then value += 1
211 end
212 values[mmodule] = value
213 end
214 end
215 end
216
217 # Module Metric: Number of Concrete Class in module (intro + redef)
218 class MNBCC
219 super MModuleMetric
220 super IntMetric
221 redef fun name do return "mnbcc"
222 redef fun desc do return "number of concrete class in module (intro + redef)"
223
224 redef fun collect(mmodules) do
225 for mmodule in mmodules do
226 var value = 0
227 for mclassdef in mmodule.mclassdefs do
228 if mclassdef.mclass.kind == concrete_kind then value += 1
229 end
230 values[mmodule] = value
231 end
232 end
233 end
234
235 # Module Metric: Number of Abstract Class in module (intro + redef)
236 class MNBAC
237 super MModuleMetric
238 super IntMetric
239 redef fun name do return "mnbac"
240 redef fun desc do return "number of abstract class in module (intro + redef)"
241
242 redef fun collect(mmodules) do
243 for mmodule in mmodules do
244 var value = 0
245 for mclassdef in mmodule.mclassdefs do
246 if mclassdef.mclass.kind == abstract_kind then value += 1
247 end
248 values[mmodule] = value
249 end
250 end
251 end
252
253 # Module Metric: Number of Interface in module (intro + redef)
254 class MNBIC
255 super MModuleMetric
256 super IntMetric
257 redef fun name do return "mnbic"
258 redef fun desc do return "number of interface in module (intro + redef)"
259
260 redef fun collect(mmodules) do
261 for mmodule in mmodules do
262 var value = 0
263 for mclassdef in mmodule.mclassdefs do
264 if mclassdef.mclass.kind == interface_kind then value += 1
265 end
266 values[mmodule] = value
267 end
268 end
269 end
270
271 # Module Metric: Number of Enum in module (intro + redef)
272 class MNBEC
273 super MModuleMetric
274 super IntMetric
275 redef fun name do return "mnbec"
276 redef fun desc do return "number of enum in module (intro + redef)"
277
278 redef fun collect(mmodules) do
279 for mmodule in mmodules do
280 var value = 0
281 for mclassdef in mmodule.mclassdefs do
282 if mclassdef.mclass.kind == enum_kind then value += 1
283 end
284 values[mmodule] = value
285 end
286 end
287 end