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