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