f9b0b15ce3aa82445347119ef747e1609ff6e549
[nit.git] / src / metrics / inheritance_metrics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.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 metrics about inheritance usage
18 module inheritance_metrics
19
20 import model
21 private import metrics_base
22
23 redef class Model
24
25 # Extract the subset of classes from a set of mclass
26 fun extract_classes(mclasses: Collection[MClass]): Set[MClass] do
27 var lst = new HashSet[MClass]
28 for mclass in mclasses do if mclass.is_class then lst.add(mclass)
29 return lst
30 end
31
32 # Extract the subset of interfaces from a set of mclass
33 fun extract_interfaces(mclasses: Collection[MClass]): Set[MClass] do
34 var lst = new HashSet[MClass]
35 for mclass in mclasses do if mclass.is_interface then lst.add(mclass)
36 return lst
37 end
38
39 # Extract the subset of generic classes/interfaces from a set of mclass
40 fun extract_generics(mclasses: Collection[MClass]): Set[MClass] do
41 var lst = new HashSet[MClass]
42 for mclass in mclasses do if mclass.arity > 0 then lst.add(mclass)
43 return lst
44 end
45
46 # Extract the subset of abstract classes from a set of mclass
47 fun extract_abstracts(mclasses: Collection[MClass]): Set[MClass] do
48 var lst = new HashSet[MClass]
49 for mclass in mclasses do if mclass.is_abstract then lst.add(mclass)
50 return lst
51 end
52
53 # Extract the subset of user defined classes/interfaces from a set of mclass
54 fun extract_user_defined(mclasses: Collection[MClass]): Set[MClass] do
55 var lst = new HashSet[MClass]
56 for mclass in mclasses do if mclass.is_user_defined then lst.add(mclass)
57 return lst
58 end
59
60 # Extract the subset of user defined modules from a set of mmodules
61 fun extract_user_defined_modules(mmodules: Collection[MModule]): Set[MModule] do
62 var lst = new HashSet[MModule]
63 for mmodule in mmodules do if mmodule.is_user_defined then lst.add(mmodule)
64 return lst
65 end
66
67 # Extract the subset of classes/interfaces from sl lib
68 fun extract_stdlib(mclasses: Collection[MClass]): Set[MClass] do
69 var lst = new HashSet[MClass]
70 for mclass in mclasses do if not mclass.is_user_defined then lst.add(mclass)
71 return lst
72 end
73
74 # Extract the subset of user defined modules from std lib
75 fun extract_stdlib_modules(mmodules: Collection[MModule]): Set[MModule] do
76 var lst = new HashSet[MModule]
77 for mmodule in mmodules do if not mmodule.is_user_defined then lst.add(mmodule)
78 return lst
79 end
80 end
81
82 redef class MModule
83 private fun is_user_defined: Bool do
84 return self.public_owner == null or self.public_owner.name != "standard"
85 end
86 end
87
88 redef class MClass
89 # Inheritance
90 private var nop: Int = 0 # (NOP) Number of parents (direct superclasses)
91 private var nopc: Int = 0 # (NOPC) Number of class parents
92 private var nopi: Int = 0 # (NOPI) Number of interface parents
93 private var noa: Int = 0 # (NOA) Number of ancestors (direct and indirect)
94 private var noac: Int = 0 # (NOAC) Number of class ancestors
95 private var noai: Int = 0 # (NOAI) Number of interface ancestors
96 private var noc: Int = 0 # (NOC) Number of children (direct subclasses)
97 private var nocc: Int = 0 # (NOCC) Number of class children
98 private var noci: Int = 0 # (NOCI) Number of interface children
99 private var nod: Int = 0 # (NOD) Number of descendants (direct and indirect)
100 private var nodc: Int = 0 # (NODC) Number of class descendants
101 private var nodi: Int = 0 # (NODI) Number of interface descendants
102 private var dit: Int = 0 # (DIT) Depth in Inheritance Tree (maximum distance to root of the hierarchy)
103 private var ditc: Int = 0 # (DITC) Length of longest path to the root hierarchy and consisting only of extends edges
104 private var diti: Int = 0 # (DITI) Length of longest path to the root hierarchy and consisting only of extends implements
105
106 # User Defined inheritance
107 private var nopud: Int = 0 # (NOPUD) Number of parents (direct superclasses)
108 private var nopcud: Int = 0 # (NOPCUD) Number of class parents
109 private var nopiud: Int = 0 # (NOPIUD) Number of interface parents
110 private var noaud: Int = 0 # (NOAUD) Number of ancestors (direct and indirect)
111 private var noacud: Int = 0 # (NOACUD) Number of class ancestors
112 private var noaiud: Int = 0 # (NOAIUD) Number of interface ancestors
113 private var nocud: Int = 0 # (NOCUD) Number of children (direct subclasses)
114 private var noccud: Int = 0 # (NOCCUD) Number of class children
115 private var nociud: Int = 0 # (NOCIUD) Number of interface children
116 private var nodud: Int = 0 # (NODUD) Number of descendants (direct and indirect)
117 private var nodcud: Int = 0 # (NODCUD) Number of class descendants
118 private var nodiud: Int = 0 # (NODIUD) Number of interface descendants
119 private var ditud: Int = 0 # (DITUD) Depth in Inheritance Tree (maximum distance to root of the hierarchy)
120 private var ditcud: Int = 0 # (DITCUD) Length of longest path to the root hierarchy and consisting only of extends edges
121 private var ditiud: Int = 0 # (DITIUD) Length of longest path to the root hierarchy and consisting only of extends implements
122
123 private fun compute_scalar_metrics(model: Model) do
124 # inheritance metrics
125 self.nop = parents.length
126 self.nopc = model.extract_classes(parents).length
127 self.nopi = model.extract_interfaces(parents).length
128 self.noa = ancestors.length
129 self.noac = model.extract_classes(ancestors).length
130 self.noai = model.extract_interfaces(ancestors).length
131 self.noc = children(model).length
132 self.nocc = model.extract_classes(children(model)).length
133 self.noci = model.extract_interfaces(children(model)).length
134 self.nod = descendants.length
135 self.nodc = model.extract_classes(descendants).length
136 self.nodi = model.extract_interfaces(descendants).length
137 self.dit = depth_from_object
138 self.ditc = model.extract_classes(path_to_object).length
139 self.diti = model.extract_interfaces(path_to_object).length
140
141 # used defined metrics
142 self.nopud = model.extract_user_defined(parents).length
143 self.nopcud = model.extract_user_defined(model.extract_classes(parents)).length
144 self.nopiud = model.extract_user_defined(model.extract_interfaces(parents)).length
145 self.noaud = model.extract_user_defined(ancestors).length
146 self.noacud = model.extract_user_defined(model.extract_classes(ancestors)).length
147 self.noaiud = model.extract_user_defined(model.extract_interfaces(ancestors)).length
148 self.nocud = model.extract_user_defined(children(model)).length
149 self.noccud = model.extract_user_defined(model.extract_classes(children(model))).length
150 self.nociud = model.extract_user_defined(model.extract_interfaces(children(model))).length
151 self.nodud = model.extract_user_defined(descendants).length
152 self.nodcud = model.extract_user_defined(model.extract_classes(descendants)).length
153 self.nodiud = model.extract_user_defined(model.extract_interfaces(descendants)).length
154 self.ditud = model.extract_user_defined(path_to_object).length
155 self.ditcud = model.extract_user_defined(model.extract_classes(path_to_object)).length
156 self.ditiud = model.extract_user_defined(model.extract_interfaces(path_to_object)).length
157 end
158
159 private fun is_class: Bool do
160 return self.kind == concrete_kind or self.kind == abstract_kind
161 end
162
163 private fun is_interface: Bool do
164 return self.kind == interface_kind
165 end
166
167 private fun is_abstract: Bool do
168 return self.kind == abstract_kind
169 end
170
171 private fun is_user_defined: Bool do
172 var mod = self.intro_mmodule.public_owner
173 return mod == null or mod.name != "standard"
174 end
175
176 # Get parents of the class (direct super classes only)
177 private fun parents: Set[MClass] do
178 var lst = new HashSet[MClass]
179 # explore all definitions of the class (refinement)
180 for mclassdef in self.mclassdefs do
181 for parent in mclassdef.supertypes do
182 lst.add(parent.mclass)
183 end
184 end
185 return lst
186 end
187
188 # Get ancestors of the class (all super classes)
189 private fun ancestors: Set[MClass] do
190 var lst = new HashSet[MClass]
191 for mclassdef in self.mclassdefs do
192 for super_mclassdef in mclassdef.in_hierarchy.greaters do
193 if super_mclassdef == mclassdef then continue # skip self
194 lst.add(super_mclassdef.mclass)
195 end
196 end
197 return lst
198 end
199
200 # Get children of the class (direct subclasses only)
201 private fun children(model: Model): Set[MClass] do
202 var lst = new HashSet[MClass]
203 for other in model.mclasses do
204 if other == self then continue # skip self
205 if other.parents.has(self) then
206 lst.add(other)
207 end
208 end
209 return lst
210 end
211
212 # Get children of the class (direct subclasses only)
213 private fun descendants: Set[MClass] do
214 var lst = new HashSet[MClass]
215 for mclassdef in self.mclassdefs do
216 for sub_mclassdef in mclassdef.in_hierarchy.smallers do
217 if sub_mclassdef == mclassdef then continue # skip self
218 lst.add(sub_mclassdef.mclass)
219 end
220 end
221 return lst
222 end
223
224 # Get the length of the longest path to Object
225 private fun depth_from_object: Int do
226 var max_depth: nullable Int = null
227
228 for parent in self.parents do
229 # direct parent is root
230 if parent.parents.is_empty then
231 return 1
232 else
233 var depth = parent.depth_from_object + 1
234 if max_depth == null then
235 max_depth = depth
236 else
237 if depth > max_depth then max_depth = depth
238 end
239 end
240 end
241 if max_depth == null then
242 return 0
243 else
244 return max_depth
245 end
246 end
247
248 # Return the longest path from class to root hierarchy
249 private fun path_to_object: Array[MClass] do
250 var path = new Array[MClass]
251 var max_dit: nullable Int = null
252 var max_parent: nullable MClass = null
253 var parent_path: nullable Array[MClass] = null
254
255 for p in parents do
256 var dit = p.depth_from_object
257 if max_dit == null or dit >= max_dit then
258 max_dit = dit
259 max_parent = p
260 parent_path = p.path_to_object
261 end
262 end
263
264 if max_parent != null and parent_path != null then
265 path.add(max_parent)
266 path.add_all(parent_path)
267 end
268
269 return path
270 end
271
272 # * -> * DUI
273
274 private fun is_dui_eligible: Bool do
275 for parent in parents do if parent.name != "Object" then return true
276 return false
277 end
278 private fun is_ccdui_eligible: Bool do
279 if not is_class then return false
280 for parent in parents do if parent.name != "Object" and parent.is_class then return true
281 return false
282 end
283 private fun is_cidui_eligible: Bool do
284 if not is_class then return false
285 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
286 return false
287 end
288 private fun is_iidui_eligible: Bool do
289 if not is_interface then return false
290 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
291 return false
292 end
293 private fun is_if_eligible(model: Model): Bool do return not children(model).is_empty
294 private fun is_ccif_eligible(model: Model): Bool do
295 if not is_class then return false
296 for child in children(model) do if child.is_class then return true
297 return false
298 end
299 private fun is_icif_eligible(model: Model): Bool do
300 if not is_interface then return false
301 for child in children(model) do if child.is_class then return true
302 return false
303 end
304 private fun is_iiif_eligible(model: Model): Bool do
305 if not is_interface then return false
306 for child in children(model) do if child.is_interface then return true
307 return false
308 end
309
310 # SL -> * DUI
311
312 private fun is_sldui_eligible: Bool do
313 if is_user_defined then return false
314 for parent in parents do if parent.name != "Object" then return true
315 return false
316 end
317 private fun is_slccdui_eligible: Bool do
318 if is_user_defined then return false
319 if not is_class then return false
320 for parent in parents do if parent.name != "Object" and parent.is_class then return true
321 return false
322 end
323 private fun is_slcidui_eligible: Bool do
324 if is_user_defined then return false
325 if not is_class then return false
326 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
327 return false
328 end
329 private fun is_sliidui_eligible: Bool do
330 if is_user_defined then return false
331 if not is_interface then return false
332 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
333 return false
334 end
335 private fun is_slif_eligible(model: Model): Bool do
336 if is_user_defined then return false
337 return not children(model).is_empty
338 end
339 private fun is_slccif_eligible(model: Model): Bool do
340 if is_user_defined then return false
341 if not is_class then return false
342 for child in children(model) do if child.is_class then return true
343 return false
344 end
345 private fun is_slicif_eligible(model: Model): Bool do
346 if is_user_defined then return false
347 if not is_interface then return false
348 for child in children(model) do if child.is_class then return true
349 return false
350 end
351 private fun is_sliiif_eligible(model: Model): Bool do
352 if is_user_defined then return false
353 if not is_interface then return false
354 for child in children(model) do if child.is_interface then return true
355 return false
356 end
357
358 # SL -> SL
359
360 private fun is_slifsl_eligible(model: Model): Bool do
361 if is_user_defined then return false
362 for child in children(model) do if not child.is_user_defined then return true
363 return false
364 end
365 private fun is_slccifsl_eligible(model: Model): Bool do
366 if is_user_defined then return false
367 if is_class then return false
368 for child in children(model) do if not child.is_user_defined and child.is_class then return true
369 return false
370 end
371 private fun is_slicifsl_eligible(model: Model): Bool do
372 if is_user_defined then return false
373 if not is_interface then return false
374 for child in children(model) do if not child.is_user_defined and child.is_class then return true
375 return false
376 end
377 private fun is_sliiifsl_eligible(model: Model): Bool do
378 if is_user_defined then return false
379 if not is_interface then return false
380 for child in children(model) do if not child.is_user_defined and child.is_interface then return true
381 return false
382 end
383
384 # SL -> UD
385
386 private fun is_slifud_eligible(model: Model): Bool do
387 if is_user_defined then return false
388 for child in children(model) do if child.is_user_defined then return true
389 return false
390 end
391 private fun is_slccifud_eligible(model: Model): Bool do
392 if is_user_defined then return false
393 if not is_class then return false
394 for child in children(model) do if child.is_user_defined and child.is_class then return true
395 return false
396 end
397 private fun is_slicifud_eligible(model: Model): Bool do
398 if is_user_defined then return false
399 if not is_interface then return false
400 for child in children(model) do if child.is_user_defined and child.is_class then return true
401 return false
402 end
403 private fun is_sliiifud_eligible(model: Model): Bool do
404 if is_user_defined then return false
405 if not is_interface then return false
406 for child in children(model) do if child.is_user_defined and child.is_interface then return true
407 return false
408 end
409
410 # UD -> *
411
412 private fun is_uddui_eligible: Bool do
413 if not is_user_defined then return false
414 for parent in parents do if parent.name != "Object" then return true
415 return false
416 end
417 private fun is_udccdui_eligible: Bool do
418 if not is_user_defined then return false
419 if not is_class then return false
420 for parent in parents do if parent.name != "Object" and parent.is_class then return true
421 return false
422 end
423 private fun is_udcidui_eligible: Bool do
424 if not is_user_defined then return false
425 if not is_class then return false
426 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
427 return false
428 end
429 private fun is_udiidui_eligible: Bool do
430 if not is_user_defined then return false
431 if not is_interface then return false
432 for parent in parents do if parent.name != "Object" and parent.is_interface then return true
433 return false
434 end
435 private fun is_udif_eligible(model: Model): Bool do
436 if not is_user_defined then return false
437 return not children(model).is_empty
438 end
439 private fun is_udccif_eligible(model: Model): Bool do
440 if not is_user_defined then return false
441 if not is_class then return false
442 for child in children(model) do if child.is_class then return true
443 return false
444 end
445 private fun is_udicif_eligible(model: Model): Bool do
446 if not is_user_defined then return false
447 if not is_interface then return false
448 for child in children(model) do if child.is_class then return true
449 return false
450 end
451 private fun is_udiiif_eligible(model: Model): Bool do
452 if not is_user_defined then return false
453 if not is_interface then return false
454 for child in children(model) do if child.is_interface then return true
455 return false
456 end
457
458 # UD -> SL
459
460 private fun is_udduisl_eligible: Bool do
461 if not is_user_defined then return false
462 for parent in parents do if not parent.is_user_defined and parent.name != "Object" then return true
463 return false
464 end
465 private fun is_udccduisl_eligible: Bool do
466 if not is_user_defined then return false
467 if not is_class then return false
468 for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_class then return true
469 return false
470 end
471 private fun is_udciduisl_eligible: Bool do
472 if not is_user_defined then return false
473 if not is_class then return false
474 for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_interface then return true
475 return false
476 end
477 private fun is_udiiduisl_eligible: Bool do
478 if not is_user_defined then return false
479 if not is_interface then return false
480 for parent in parents do if not parent.is_user_defined and parent.name != "Object" and parent.is_interface then return true
481 return false
482 end
483
484 # UD -> UD
485
486 private fun is_udduiud_eligible: Bool do
487 if not is_user_defined then return false
488 for parent in parents do if parent.name != "Object" and parent.is_user_defined then return true
489 return false
490 end
491 private fun is_udccduiud_eligible: Bool do
492 if not is_user_defined then return false
493 if not is_class then return false
494 for parent in parents do if parent.name != "Object" and parent.is_class and parent.is_user_defined then return true
495 return false
496 end
497 private fun is_udciduiud_eligible: Bool do
498 if not is_user_defined then return false
499 if not is_class then return false
500 for parent in parents do if parent.name != "Object" and parent.is_interface and parent.is_user_defined then return true
501 return false
502 end
503 private fun is_udiiduiud_eligible: Bool do
504 if not is_user_defined then return false
505 if not is_interface then return false
506 for parent in parents do if parent.name != "Object" and parent.is_interface and parent.is_user_defined then return true
507 return false
508 end
509 private fun is_udifud_eligible(model: Model): Bool do
510 if not is_user_defined then return false
511 return not children(model).is_empty
512 end
513 private fun is_udccifud_eligible(model: Model): Bool do
514 if not is_user_defined then return false
515 if not is_class then return false
516 for child in children(model) do if child.is_user_defined and child.is_class then return true
517 return false
518 end
519 private fun is_udicifud_eligible(model: Model): Bool do
520 if not is_user_defined then return false
521 if not is_interface then return false
522 for child in children(model) do if child.is_user_defined and child.is_class then return true
523 return false
524 end
525 private fun is_udiiifud_eligible(model: Model): Bool do
526 if not is_user_defined then return false
527 if not is_interface then return false
528 for child in children(model) do if child.is_user_defined and child.is_interface then return true
529 return false
530 end
531
532 end
533
534 # Print inheritance usage metrics
535 fun compute_inheritance_metrics(toolcontext: ToolContext, model: Model)
536 do
537 # global summary metrics
538 var nmd: Int = 0 # (NMD) Number of Modules
539 var nc: Int = 0 # (NC) Number of Classes
540 var ni: Int = 0 # (NI) Number of Interfaces
541 var nac : Int = 0 # (NAC) Number of Abstract Classes
542 var ngc : Int = 0 # (NGC) Number of Generic Classes
543 var ngi : Int = 0 # (NGI) Number of Generic Interfaces
544 # (SL) Std-Lib summary metrics
545 var nmdsl: Int = 0 # (NMDSL) Number of Modules in Std-Lib
546 var ncsl: Int = 0 # (NCSL) Number of Classes in Std-Lib
547 var nisl: Int = 0 # (NISL) Number of Interfaces in Std-Lib
548 var nacsl : Int = 0 # (NACSL) Number of Abstract Classes in Std-Lib
549 var ngcsl : Int = 0 # (NGCSL) Number of Generic Classes in Std-Lib
550 var ngisl : Int = 0 # (NGISL) Number of Generic Interfaces in Std-Lib
551 # (UD) User-Defined summary metrics
552 var nmdud: Int = 0 # (NMDUD) Number of Modules User Defined
553 var ncud: Int = 0 # (NCUD) Number of Classes User Defined
554 var niud: Int = 0 # (NIUD) Number of Interfaces User Defined
555 var nacud : Int = 0 # (NACUD) Number of Abstract Classes User Defined
556 var ngcud : Int = 0 # (NGCUD) Number of Generic Classes User Defined
557 var ngiud : Int = 0 # (NGIUD) Number of Generic Interfaces User Defined
558
559 # global summary inheritance metrics
560 var dit = "" # (DIT) Global Depth in Inheritance Tree
561 var dui = "" # (DUI) Proportion of types that either implement an interface or extend another type other than Object
562 var ccdui = "" # (CCDUI) Proportion of classes that extend some other class.
563 var cidui = "" # (CIDUI) Proportion of classes that implement some other interface.
564 var iidui = "" # (IIDUI) Proportion of interfaces that extend some other interface.
565 var inhf = "" # (IF) Proportion of types Inherited From, that is, those types that are either extended or implemented
566 var ccif = "" # (CCIF) Proportion of classes extended by some other class.
567 var icif = "" # (ICIF) Proportion of interfaces implemented by some other class.
568 var iiif = "" # (IIIF) Proportion of interfaces extended by some other interface.
569
570 # (SL -> *) Std-Lib summary inheritance metrics
571 var sldui = "" # (SLDUI) Proportion of std-lib types that either implement an interface or extend another std-lib type other than Object
572 var slccdui = "" # (SLCCDUI) Proportion of std-lib classes that extend some other std-lib class.
573 var slcidui = "" # (SLCIDUI) Proportion of std-lib classes that implement some other std-lib interface.
574 var sliidui = "" # (SLIIDUI) Proportion of std-lib interfaces that extend some other std-lib interface.
575 var slinhf = "" # (SLIF) Proportion of SL types Inherited From, that is, those types that are either extended or implemented
576 var slccif = "" # (SLCCIF) Proportion of SL classes extended by some other class.
577 var slicif = "" # (SLICIF) Proportion of SL interfaces implemented by some other class.
578 var sliiif = "" # (SLIIIF) Proportion of SL interfaces extended by some other interface.
579
580 # (SL -> SL) Std-Lib summary inheritance metrics
581 var slinhfsl = "" # (SLIFSL) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a SL type
582 var slccifsl = "" # (SLCCIFSL) Proportion of SL classes extended by some other SL class.
583 var slicifsl = "" # (SLICIFSL) Proportion of SL interfaces implemented by some other SL class.
584 var sliiifsl = "" # (SLIIIFSL) Proportion of SL interfaces extended by some other SL interface.
585
586 # (SL -> UD) Std-Lib summary inheritance metrics
587 var slinhfud = "" # (SLIFUD) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a UD type
588 var slccifud = "" # (SLCCIFUD) Proportion of SL classes extended by some other UD class.
589 var slicifud = "" # (SLICIFUD) Proportion of SL interfaces implemented by some other UD class.
590 var sliiifud = "" # (SLIIIFUD) Proportion of SL interfaces extended by some other UD interface.
591
592 # (UD -> *) User-defined summary inheritance metrics
593 var uddui = "" # (UDDUI) Proportion user-defined of types that either implement an interface or extend another type
594 var udccdui = "" # (UDCCDUI) Proportion of user-defined classes that extend some other class.
595 var udcidui = "" # (UDCIDUI) Proportion of user-defined classes that implement some other interface.
596 var udiidui = "" # (UDIIDUI) Proportion of user-defined interfaces that extend some other interface.
597 var udinhf = "" # (UDIF) Proportion of UD types Inherited From, that is, those types that are either extended or implemented
598 var udccif = "" # (UDCCIF) Proportion of UD classes extended by some other class.
599 var udicif = "" # (UDICIF) Proportion of UD interfaces implemented by some other class.
600 var udiiif = "" # (UDIIIF) Proportion of UD interfaces extended by some other interface.
601
602 # (UD -> SL) User-defined summary inheritance metrics
603 var udduisl = "" # (UDDUISL) Proportion user-defined of types that either implement an interface or extend another type SL
604 var udccduisl = "" # (UDCCDUISL) Proportion of user-defined classes that extend some other SL class.
605 var udciduisl = "" # (UDCIDUISL) Proportion of user-defined classes that implement some other SL interface.
606 var udiiduisl = "" # (UDIIDUISL) Proportion of user-defined interfaces that extend some other SL interface.
607
608 # (UD -> UD) User-defined summary inheritance metrics
609 var udduiud = "" # (UDDUIUD) Proportion user-defined of types that either implement an interface or extend another type user-defined
610 var udccduiud = "" # (UDCCDUIUD) Proportion of user-defined classes that extend some other user-defined class.
611 var udciduiud = "" # (UDCIDUIUD) Proportion of user-defined classes that implement some other user-defined interface.
612 var udiiduiud = "" # (UDIIDUIUD) Proportion of user-defined interfaces that extend some other user-defined interface.
613 var udinhfud = "" # (UDIFUD) Proportion of UD types Inherited From, that is, those types that are either extended or implemented by another UD type
614 var udccifud = "" # (UDCCIFUD) Proportion of UD classes extended by some other UD class.
615 var udicifud = "" # (UDICIFUD) Proportion of UD interfaces implemented by some other UD class.
616 var udiiifud = "" # (UDIIIFUD) Proportion of UD interfaces extended by some other UD interface.
617
618 # compute scalar metrics
619 for mclass in model.mclasses do
620 mclass.compute_scalar_metrics(model)
621 end
622
623 # compute summary metrics
624
625 # compute global summary metrics
626 nmd = model.mmodules.length
627 nc = model.extract_classes(model.mclasses).length
628 ni = model.extract_interfaces(model.mclasses).length
629 nac = model.extract_abstracts(model.mclasses).length
630 ngc = model.extract_generics(model.extract_classes(model.mclasses)).length
631 ngi = model.extract_generics(model.extract_interfaces(model.mclasses)).length
632 # compute std-lib summary metrics
633 nmdsl = model.extract_stdlib_modules(model.mmodules).length
634 ncsl = model.extract_stdlib(model.extract_classes(model.mclasses)).length
635 nisl = model.extract_stdlib(model.extract_interfaces(model.mclasses)).length
636 nacsl = model.extract_stdlib(model.extract_abstracts(model.mclasses)).length
637 ngcsl = model.extract_stdlib(model.extract_generics(model.extract_classes(model.mclasses))).length
638 ngisl = model.extract_stdlib(model.extract_generics(model.extract_interfaces(model.mclasses))).length
639 # compute user-defined summary metrics
640 nmdud = model.extract_user_defined_modules(model.mmodules).length
641 ncud = model.extract_user_defined(model.extract_classes(model.mclasses)).length
642 niud = model.extract_user_defined(model.extract_interfaces(model.mclasses)).length
643 nacud = model.extract_user_defined(model.extract_abstracts(model.mclasses)).length
644 ngcud = model.extract_user_defined(model.extract_generics(model.extract_classes(model.mclasses))).length
645 ngiud = model.extract_user_defined(model.extract_generics(model.extract_interfaces(model.mclasses))).length
646
647 # compute inheritance summary metrics
648
649 # * -> *
650 var ditsum = 0
651 var dui_count = 0
652 var ccdui_count = 0
653 var cidui_count = 0
654 var iidui_count = 0
655 var if_count = 0
656 var ccif_count = 0
657 var icif_count = 0
658 var iiif_count = 0
659
660 # SL -> *
661 var sldui_count = 0
662 var slccdui_count = 0
663 var slcidui_count = 0
664 var sliidui_count = 0
665 var slif_count = 0
666 var slccif_count = 0
667 var slicif_count = 0
668 var sliiif_count = 0
669
670 # SL -> SL
671 var slifsl_count = 0
672 var slccifsl_count = 0
673 var slicifsl_count = 0
674 var sliiifsl_count = 0
675
676 # SL -> UD
677 var slifud_count = 0
678 var slccifud_count = 0
679 var slicifud_count = 0
680 var sliiifud_count = 0
681
682 # UD -> *
683 var uddui_count = 0
684 var udccdui_count = 0
685 var udcidui_count = 0
686 var udiidui_count = 0
687 var udif_count = 0
688 var udccif_count = 0
689 var udicif_count = 0
690 var udiiif_count = 0
691
692 # UD -> SL
693 var udduisl_count = 0
694 var udccduisl_count = 0
695 var udciduisl_count = 0
696 var udiiduisl_count = 0
697
698 # UD -> UD
699 var udduiud_count = 0
700 var udccduiud_count = 0
701 var udciduiud_count = 0
702 var udiiduiud_count = 0
703 var udifud_count = 0
704 var udccifud_count = 0
705 var udicifud_count = 0
706 var udiiifud_count = 0
707
708 for mclass in model.mclasses do
709 ditsum += mclass.dit
710
711 # * -> *
712 if mclass.is_dui_eligible then dui_count += 1
713 if mclass.is_ccdui_eligible then ccdui_count += 1
714 if mclass.is_cidui_eligible then cidui_count += 1
715 if mclass.is_iidui_eligible then iidui_count += 1
716 if mclass.is_if_eligible(model) then if_count += 1
717 if mclass.is_ccif_eligible(model) then ccif_count += 1
718 if mclass.is_icif_eligible(model) then icif_count += 1
719 if mclass.is_iiif_eligible(model) then iiif_count += 1
720
721 # SL -> *
722 if mclass.is_sldui_eligible then sldui_count += 1
723 if mclass.is_slccdui_eligible then slccdui_count += 1
724 if mclass.is_slcidui_eligible then slcidui_count += 1
725 if mclass.is_sliidui_eligible then sliidui_count += 1
726 if mclass.is_slif_eligible(model) then slif_count += 1
727 if mclass.is_slccif_eligible(model) then slccif_count += 1
728 if mclass.is_slicif_eligible(model) then slicif_count += 1
729 if mclass.is_sliiif_eligible(model) then sliiif_count += 1
730
731 # SL -> SL
732 if mclass.is_slifsl_eligible(model) then slifsl_count += 1
733 if mclass.is_slccifsl_eligible(model) then slccifsl_count += 1
734 if mclass.is_slicifsl_eligible(model) then slicifsl_count += 1
735 if mclass.is_sliiifsl_eligible(model) then sliiifsl_count += 1
736
737 # SL -> UD
738 if mclass.is_slifud_eligible(model) then slifud_count += 1
739 if mclass.is_slccifud_eligible(model) then slccifud_count += 1
740 if mclass.is_slicifud_eligible(model) then slicifud_count += 1
741 if mclass.is_sliiifud_eligible(model) then sliiifud_count += 1
742
743 # UD -> *
744 if mclass.is_uddui_eligible then uddui_count += 1
745 if mclass.is_udccdui_eligible then udccdui_count += 1
746 if mclass.is_udcidui_eligible then udcidui_count += 1
747 if mclass.is_udiidui_eligible then udiidui_count += 1
748 if mclass.is_udif_eligible(model) then udif_count += 1
749 if mclass.is_udccif_eligible(model) then udccif_count += 1
750 if mclass.is_udicif_eligible(model) then udicif_count += 1
751 if mclass.is_udiiif_eligible(model) then udiiif_count += 1
752
753 # UD -> SL
754 if mclass.is_udduisl_eligible then udduisl_count += 1
755 if mclass.is_udccduisl_eligible then udccduisl_count += 1
756 if mclass.is_udciduisl_eligible then udciduisl_count += 1
757 if mclass.is_udiiduisl_eligible then udiiduisl_count += 1
758
759 # UD -> UD
760 if mclass.is_udduiud_eligible then udduiud_count += 1
761 if mclass.is_udccduiud_eligible then udccduiud_count += 1
762 if mclass.is_udciduiud_eligible then udciduiud_count += 1
763 if mclass.is_udiiduiud_eligible then udiiduiud_count += 1
764 if mclass.is_udifud_eligible(model) then udifud_count += 1
765 if mclass.is_udccifud_eligible(model) then udccifud_count += 1
766 if mclass.is_udicifud_eligible(model) then udicifud_count += 1
767 if mclass.is_udiiifud_eligible(model) then udiiifud_count += 1
768 end
769
770 # * -> *
771 dit = div(ditsum, model.mclasses.length)
772 dui = div(dui_count * 100, nc + ni)
773 ccdui = div(ccdui_count * 100, nc)
774 cidui = div(cidui_count * 100, nc)
775 iidui = div(iidui_count * 100, ni)
776 inhf = div(if_count * 100, nc + ni)
777 ccif = div(ccif_count * 100, nc)
778 icif = div(icif_count * 100, ni)
779 iiif = div(iiif_count * 100, ni)
780
781 # SL -> *
782 sldui = div(sldui_count * 100, ncsl + nisl)
783 slccdui = div(slccdui_count * 100, ncsl)
784 slcidui = div(slcidui_count * 100, ncsl)
785 sliidui = div(sliidui_count * 100, nisl)
786 slinhf = div(slif_count * 100, ncsl + nisl)
787 slccif = div(slccif_count * 100, ncsl)
788 slicif = div(slicif_count * 100, nisl)
789 sliiif = div(sliiif_count * 100, nisl)
790
791 # SL -> SL
792 slinhfsl = div(slifsl_count * 100, ncsl + nisl)
793 slccifsl = div(slccifsl_count * 100, ncsl)
794 slicifsl = div(slicifsl_count * 100, nisl)
795 sliiifsl = div(sliiifsl_count * 100, nisl)
796
797 # SL -> UD
798 slinhfud = div(slifud_count * 100, ncsl + nisl)
799 slccifud = div(slccifud_count * 100, ncsl)
800 slicifud = div(slicifud_count * 100, nisl)
801 sliiifud = div(sliiifud_count * 100, nisl)
802
803 # UD -> *
804 uddui = div(uddui_count * 100, ncud + niud)
805 udccdui = div(udccdui_count * 100, ncud)
806 udcidui = div(udcidui_count * 100, ncud)
807 udiidui = div(udiidui_count * 100, niud)
808 udinhf = div(if_count * 100, ncud + niud)
809 udccif = div(ccif_count * 100, ncud)
810 udicif = div(icif_count * 100, niud)
811 udiiif = div(iiif_count * 100, niud)
812
813 # UD -> SL
814 udduisl = div(udduisl_count * 100, ncud + niud)
815 udccduisl = div(udccduisl_count * 100, ncud)
816 udciduisl = div(udciduisl_count * 100, ncud)
817 udiiduisl = div(udiiduisl_count * 100, niud)
818
819 # UD -> UD
820 udduiud = div(udduiud_count * 100, ncud + niud)
821 udccduiud = div(udccduiud_count * 100, ncud)
822 udciduiud = div(udciduiud_count * 100, ncud)
823 udiiduiud = div(udiiduiud_count * 100, niud)
824 udinhfud = div(udifud_count * 100, ncud + niud)
825 udccifud = div(udccifud_count * 100, ncud)
826 udicifud = div(udicifud_count * 100, niud)
827 udiiifud = div(udiiifud_count * 100, niud)
828
829 # CSV generation
830 if toolcontext.opt_generate_csv.value then
831 # summary_metrics
832 var summaryCSV = new CSVDocument(toolcontext.output_dir.join_path("summary_metrics.csv"))
833 summaryCSV.set_header("scope", "NMD", "NC", "NI", "NAC", "NGC", "NGI")
834 summaryCSV.add_line("global", nmd, nc, ni, nac, ngc, ngi)
835 summaryCSV.add_line("std-lib", nmdsl, ncsl, nisl, nacsl, ngcsl, ngisl)
836 summaryCSV.add_line("user-defined", nmdud, ncud, niud, nacud, ngcud, ngiud)
837 summaryCSV.save
838
839 # inheritance metrics
840 var inheritanceCSV = new CSVDocument(toolcontext.output_dir.join_path("inheritance_metrics.csv"))
841 inheritanceCSV.set_header("scope", "DIT", "DUI", "CCDUI", "CIDUI", "IIDUI", "IF", "CCIF", "ICIF", "IIIF")
842 inheritanceCSV.add_line("global", dit, dui, ccdui, cidui, iidui, inhf, ccif, icif, iiif)
843 inheritanceCSV.add_line("SL -> *", "", sldui, slccdui, slcidui, sliidui, slinhf, slccif, slicif, sliiif)
844 inheritanceCSV.add_line("SL -> SL", "", sldui, slccdui, slcidui, sliidui, slinhfsl, slccifsl, slicifsl, sliiifsl)
845 inheritanceCSV.add_line("SL -> UD", "", 0, 0, 0, 0, slinhfud, slccifud, slicifud, sliiifud)
846 inheritanceCSV.add_line("UD -> *", "", uddui, udccdui, udcidui, udiidui, udinhf, udccif, udicif, udiiif)
847 inheritanceCSV.add_line("UD -> SL", "", udduisl, udccduisl, udciduisl, udiiduisl, 0, 0, 0, 0)
848 inheritanceCSV.add_line("UD -> UD", "", udduiud, udccduiud, udciduiud, udiiduiud, udinhfud, udccifud, udicifud, udiiifud)
849 inheritanceCSV.save
850
851 # scalar metrics
852 var scalarCSV = new CSVDocument(toolcontext.output_dir.join_path("global_scalar_metrics.csv"))
853 var udscalarCSV = new CSVDocument(toolcontext.output_dir.join_path("ud_scalar_metrics.csv"))
854 scalarCSV.set_header("mclass", "type", "DIT", "DITC", "DITI", "NOP", "NOPC", "NOPI", "NOA", "NOAC", "NOAI", "NOC", "NOCC", "NOCI", "NOD", "NODC", "NODI")
855 udscalarCSV.set_header("mclass", "type", "DITUD", "DITCUD", "DITIUD", "NOPUD", "NOPCUD", "NOPIUD", "NOAUD", "NOACUD", "NOAIUD", "NOCUD", "NOCCUD", "NOCIUD", "NODUD", "NODCUD", "NODIUD")
856 for mclass in model.mclasses do
857 var name = mclass.name
858 var typ = "class"
859 if mclass.is_interface then typ = "interface"
860 scalarCSV.add_line(name, typ, mclass.dit, mclass.ditc, mclass.diti, mclass.nop, mclass.nopc, mclass.nopi, mclass.noa, mclass.noac, mclass.noai, mclass.noc, mclass.nocc, mclass.noci, mclass.nod, mclass.nodc, mclass.nodi)
861 udscalarCSV.add_line(name, typ, mclass.ditud, mclass.ditcud, mclass.ditiud, mclass.nopud, mclass.nopcud, mclass.nopiud, mclass.noaud, mclass.noacud, mclass.noaiud, mclass.nocud, mclass.noccud, mclass.nociud, mclass.nodud, mclass.nodcud, mclass.nodiud)
862 end
863 scalarCSV.save
864 udscalarCSV.save
865 end
866
867 print "--- Global Summary metrics ---"
868 print "(NMD) Number of Modules: {nmd}"
869 print "(NC) Number of Classes: {nc}"
870 print "(NI) Number of Interfaces: {ni}"
871 print "(NAC) Number of Abstract Classes: {nac}"
872 print "(NGC) Number of Generic Classes: {ngc}"
873 print "(NGI) Number of Generic Interfaces: {ngi}"
874 print "--- (SL) Std-Lib Summary metrics ---"
875 print "(NMDSL) Number of Modules: {nmdsl}"
876 print "(NCSL) Number of Classes: {ncsl}"
877 print "(NISL) Number of Interfaces: {nisl}"
878 print "(NACSL) Number of Abstract Classes: {nacsl}"
879 print "(NGCSL) Number of Generic Classes: {ngcsl}"
880 print "(NGISL) Number of Generic Interfaces: {ngisl}"
881 print "--- (UD) User-Defined Summary metrics ---"
882 print "(NMDUD) Number of Modules: {nmdud}"
883 print "(NCUD) Number of Classes: {ncud}"
884 print "(NIUD) Number of Interfaces: {niud}"
885 print "(NACUD) Number of Abstract Classes: {nacud}"
886 print "(NGCUD) Number of Generic Classes: {ngcud}"
887 print "(NGIUD) Number of Generic Interfaces: {ngiud}"
888 print ""
889 print "--- Global Inheritance metrics ---"
890 print "(DIT) Global Depth in Inheritance Tree: {dit}"
891 print "(DUI) Proportion of types inheriting another type other than Object: {dui}%"
892 print "(CCDUI) Proportion of classes that extend some other class: {ccdui}%"
893 print "(CIDUI) Proportion of classes that implement some other interface: {cidui}%"
894 print "(IIDUI) Proportion of interfaces that extend some other interface: {iidui}%"
895 print "(IF) Proportion of types Inherited From: {inhf}%"
896 print "(CCIF) Proportion of classes extended by class: {ccif}%"
897 print "(ICIF) Proportion of interfaces implemented by class: {icif}%"
898 print "(IIIF) Proportion of interfaces extended by interface: {iiif}%"
899 print ""
900 print "--- (SL -> *) Std-Lib Inheritance metrics ---"
901 print "(SLDUI) Proportion of SL types inheriting another type other than Object: {sldui}%"
902 print "(SLCCDUI) Proportion of SL classes that extend some other class: {slccdui}%"
903 print "(SLCIDUI) Proportion of SL classes that implement some other interface: {slcidui}%"
904 print "(SLIIDUI) Proportion of SL interfaces that extend some other interface: {sliidui}%"
905 print "(SLIF) Proportion of SL types Inherited From: {slinhf}%"
906 print "(SLCCIF) Proportion of SL classes extended by class: {slccif}%"
907 print "(SLICIF) Proportion of SL interfaces implemented by class: {slicif}%"
908 print "(SLIIIF) Proportion of SL interfaces extended by interface: {sliiif}%"
909 print ""
910 print "--- (SL -> SL) Std-Lib Inheritance metrics ---"
911 print "(SLIFSL) Proportion of SL types Inherited From by SL type: {slinhfsl}%"
912 print "(SLCCIFSL) Proportion of SL classes extended by SL class: {slccifsl}%"
913 print "(SLICIFSL) Proportion of SL interfaces implemented by SL class: {slicifsl}%"
914 print "(SLIIIFSL) Proportion of SL interfaces extended by SL interface: {sliiifsl}%"
915 print ""
916 print "--- (SL->UD) Std-Lib Inheritance metrics ---"
917 print "(SLIFUD) Proportion of SL types Inherited From by UD type: {slinhfud}%"
918 print "(SLCCIFUD) Proportion of SL classes extended by UD class: {slccifud}%"
919 print "(SLICIFUD) Proportion of SL interfaces implemented by UD class: {slicifud}%"
920 print "(SLIIIFUD) Proportion of SL interfaces extended by UD interface: {sliiifud}%"
921 print ""
922 print "--- (UD->*) User-Defined Inheritance metrics ---"
923 print "(UDDUI) Proportion of UD types inheriting another type other than Object: {uddui}%"
924 print "(UDCCDUI) Proportion of UD classes that extend some other class: {udccdui}%"
925 print "(UDCIDUI) Proportion of UD classes that implement some other interface: {udcidui}%"
926 print "(UDIIDUI) Proportion of UD interfaces that extend some other interface: {udiidui}%"
927 print "(UDIF) Proportion of UD types Inherited From: {udinhf}%"
928 print "(UDCCIF) Proportion of UD classes extended by class: {udccif}%"
929 print "(UDICIF) Proportion of UD interfaces implemented by class: {udicif}%"
930 print "(UDIIIF) Proportion of UD interfaces extended by interface: {udiiif}%"
931 print ""
932 print "--- (UD -> SL) User-Defined Inheritance metrics ---"
933 print "(UDDUISL) Proportion of UD types inheriting another type other SL type: {udduisl}%"
934 print "(UDCCDUISL) Proportion of UD classes that extend some other SL class: {udccduisl}%"
935 print "(UDCIDUISL) Proportion of UD classes that implement some other SL interface: {udciduisl}%"
936 print "(UDIIDUISL) Proportion of UD interfaces that extend some other SL interface: {udiiduisl}%"
937 print ""
938 print "--- (UD -> UD) User-Defined Inheritance metrics ---"
939 print "(UDDUIUD) Proportion of UD types inheriting another type other UD type: {udduiud}%"
940 print "(UDCCDUIUD) Proportion of UD classes that extend some other UD class: {udccduiud}%"
941 print "(UDCIDUIUD) Proportion of UD classes that implement some other UD interface: {udciduiud}%"
942 print "(UDIIDUIUD) Proportion of UD interfaces that extend some other UD interface: {udiiduiud}%"
943 print "(UDIFUD) Proportion of UD types Inherited From: {udinhfud}%"
944 print "(UDCCIFUD) Proportion of UD classes extended by UD class: {udccifud}%"
945 print "(UDICIFUD) Proportion of UD interfaces implemented by UD class: {udicifud}%"
946 print "(UDIIIFUD) Proportion of UD interfaces extended by UD interface: {udiiifud}%"
947 end
948
949 # TODO Third-Party metrics
950 # TODO CSV generation
951 # TODO gnu-plot generation