1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Collect metrics about inheritance usage
18 module inheritance_metrics
21 private import metrics_base
25 # Extract the subset of classes from a set of mclass
26 fun extract_classes
(mclasses
: Collection[MClass]): Set[MClass] do
27 var lst
= new HashSet[MClass]
28 for mclass
in mclasses
do if mclass
.is_class
then lst
.add
(mclass
)
32 # Extract the subset of interfaces from a set of mclass
33 fun extract_interfaces
(mclasses
: Collection[MClass]): Set[MClass] do
34 var lst
= new HashSet[MClass]
35 for mclass
in mclasses
do if mclass
.is_interface
then lst
.add
(mclass
)
39 # Extract the subset of generic classes/interfaces from a set of mclass
40 fun extract_generics
(mclasses
: Collection[MClass]): Set[MClass] do
41 var lst
= new HashSet[MClass]
42 for mclass
in mclasses
do if mclass
.arity
> 0 then lst
.add
(mclass
)
46 # Extract the subset of abstract classes from a set of mclass
47 fun extract_abstracts
(mclasses
: Collection[MClass]): Set[MClass] do
48 var lst
= new HashSet[MClass]
49 for mclass
in mclasses
do if mclass
.is_abstract
then lst
.add
(mclass
)
53 # Extract the subset of user defined classes/interfaces from a set of mclass
54 fun extract_user_defined
(mclasses
: Collection[MClass]): Set[MClass] do
55 var lst
= new HashSet[MClass]
56 for mclass
in mclasses
do if mclass
.is_user_defined
then lst
.add
(mclass
)
60 # Extract the subset of user defined modules from a set of mmodules
61 fun extract_user_defined_modules
(mmodules
: Collection[MModule]): Set[MModule] do
62 var lst
= new HashSet[MModule]
63 for mmodule
in mmodules
do if mmodule
.is_user_defined
then lst
.add
(mmodule
)
67 # Extract the subset of classes/interfaces from sl lib
68 fun extract_stdlib
(mclasses
: Collection[MClass]): Set[MClass] do
69 var lst
= new HashSet[MClass]
70 for mclass
in mclasses
do if not mclass
.is_user_defined
then lst
.add
(mclass
)
74 # Extract the subset of user defined modules from std lib
75 fun extract_stdlib_modules
(mmodules
: Collection[MModule]): Set[MModule] do
76 var lst
= new HashSet[MModule]
77 for mmodule
in mmodules
do if not mmodule
.is_user_defined
then lst
.add
(mmodule
)
83 private fun is_user_defined
: Bool do
84 return self.public_owner
== null or self.public_owner
.name
!= "standard"
90 private var nop
: Int = 0 # (NOP) Number of parents (direct superclasses)
91 private var nopc
: Int = 0 # (NOPC) Number of class parents
92 private var nopi
: Int = 0 # (NOPI) Number of interface parents
93 private var noa
: Int = 0 # (NOA) Number of ancestors (direct and indirect)
94 private var noac
: Int = 0 # (NOAC) Number of class ancestors
95 private var noai
: Int = 0 # (NOAI) Number of interface ancestors
96 private var noc
: Int = 0 # (NOC) Number of children (direct subclasses)
97 private var nocc
: Int = 0 # (NOCC) Number of class children
98 private var noci
: Int = 0 # (NOCI) Number of interface children
99 private var nod
: Int = 0 # (NOD) Number of descendants (direct and indirect)
100 private var nodc
: Int = 0 # (NODC) Number of class descendants
101 private var nodi
: Int = 0 # (NODI) Number of interface descendants
102 private var dit
: Int = 0 # (DIT) Depth in Inheritance Tree (maximum distance to root of the hierarchy)
103 private var ditc
: Int = 0 # (DITC) Length of longest path to the root hierarchy and consisting only of extends edges
104 private var diti
: Int = 0 # (DITI) Length of longest path to the root hierarchy and consisting only of extends implements
106 # User Defined inheritance
107 private var nopud
: Int = 0 # (NOPUD) Number of parents (direct superclasses)
108 private var nopcud
: Int = 0 # (NOPCUD) Number of class parents
109 private var nopiud
: Int = 0 # (NOPIUD) Number of interface parents
110 private var noaud
: Int = 0 # (NOAUD) Number of ancestors (direct and indirect)
111 private var noacud
: Int = 0 # (NOACUD) Number of class ancestors
112 private var noaiud
: Int = 0 # (NOAIUD) Number of interface ancestors
113 private var nocud
: Int = 0 # (NOCUD) Number of children (direct subclasses)
114 private var noccud
: Int = 0 # (NOCCUD) Number of class children
115 private var nociud
: Int = 0 # (NOCIUD) Number of interface children
116 private var nodud
: Int = 0 # (NODUD) Number of descendants (direct and indirect)
117 private var nodcud
: Int = 0 # (NODCUD) Number of class descendants
118 private var nodiud
: Int = 0 # (NODIUD) Number of interface descendants
119 private var ditud
: Int = 0 # (DITUD) Depth in Inheritance Tree (maximum distance to root of the hierarchy)
120 private var ditcud
: Int = 0 # (DITCUD) Length of longest path to the root hierarchy and consisting only of extends edges
121 private var ditiud
: Int = 0 # (DITIUD) Length of longest path to the root hierarchy and consisting only of extends implements
123 private fun compute_scalar_metrics
(model
: Model) do
124 # inheritance metrics
125 self.nop
= parents
.length
126 self.nopc
= model
.extract_classes
(parents
).length
127 self.nopi
= model
.extract_interfaces
(parents
).length
128 self.noa
= ancestors
.length
129 self.noac
= model
.extract_classes
(ancestors
).length
130 self.noai
= model
.extract_interfaces
(ancestors
).length
131 self.noc
= children
(model
).length
132 self.nocc
= model
.extract_classes
(children
(model
)).length
133 self.noci
= model
.extract_interfaces
(children
(model
)).length
134 self.nod
= descendants
.length
135 self.nodc
= model
.extract_classes
(descendants
).length
136 self.nodi
= model
.extract_interfaces
(descendants
).length
137 self.dit
= depth_from_object
138 self.ditc
= model
.extract_classes
(path_to_object
).length
139 self.diti
= model
.extract_interfaces
(path_to_object
).length
141 # used defined metrics
142 self.nopud
= model
.extract_user_defined
(parents
).length
143 self.nopcud
= model
.extract_user_defined
(model
.extract_classes
(parents
)).length
144 self.nopiud
= model
.extract_user_defined
(model
.extract_interfaces
(parents
)).length
145 self.noaud
= model
.extract_user_defined
(ancestors
).length
146 self.noacud
= model
.extract_user_defined
(model
.extract_classes
(ancestors
)).length
147 self.noaiud
= model
.extract_user_defined
(model
.extract_interfaces
(ancestors
)).length
148 self.nocud
= model
.extract_user_defined
(children
(model
)).length
149 self.noccud
= model
.extract_user_defined
(model
.extract_classes
(children
(model
))).length
150 self.nociud
= model
.extract_user_defined
(model
.extract_interfaces
(children
(model
))).length
151 self.nodud
= model
.extract_user_defined
(descendants
).length
152 self.nodcud
= model
.extract_user_defined
(model
.extract_classes
(descendants
)).length
153 self.nodiud
= model
.extract_user_defined
(model
.extract_interfaces
(descendants
)).length
154 self.ditud
= model
.extract_user_defined
(path_to_object
).length
155 self.ditcud
= model
.extract_user_defined
(model
.extract_classes
(path_to_object
)).length
156 self.ditiud
= model
.extract_user_defined
(model
.extract_interfaces
(path_to_object
)).length
159 private fun is_class
: Bool do
160 return self.kind
== concrete_kind
or self.kind
== abstract_kind
163 private fun is_interface
: Bool do
164 return self.kind
== interface_kind
167 private fun is_abstract
: Bool do
168 return self.kind
== abstract_kind
171 private fun is_user_defined
: Bool do
172 var mod
= self.intro_mmodule
.public_owner
173 return mod
== null or mod
.name
!= "standard"
176 # Get parents of the class (direct super classes only)
177 private fun parents
: Set[MClass] do
178 var lst
= new HashSet[MClass]
179 # explore all definitions of the class (refinement)
180 for mclassdef
in self.mclassdefs
do
181 for parent
in mclassdef
.supertypes
do
182 lst
.add
(parent
.mclass
)
188 # Get ancestors of the class (all super classes)
189 private fun ancestors
: Set[MClass] do
190 var lst
= new HashSet[MClass]
191 for mclassdef
in self.mclassdefs
do
192 for super_mclassdef
in mclassdef
.in_hierarchy
.greaters
do
193 if super_mclassdef
== mclassdef
then continue # skip self
194 lst
.add
(super_mclassdef
.mclass
)
200 # Get children of the class (direct subclasses only)
201 private fun children
(model
: Model): Set[MClass] do
202 var lst
= new HashSet[MClass]
203 for other
in model
.mclasses
do
204 if other
== self then continue # skip self
205 if other
.parents
.has
(self) then
212 # Get children of the class (direct subclasses only)
213 private fun descendants
: Set[MClass] do
214 var lst
= new HashSet[MClass]
215 for mclassdef
in self.mclassdefs
do
216 for sub_mclassdef
in mclassdef
.in_hierarchy
.smallers
do
217 if sub_mclassdef
== mclassdef
then continue # skip self
218 lst
.add
(sub_mclassdef
.mclass
)
224 # Get the length of the longest path to Object
225 private fun depth_from_object
: Int do
226 var max_depth
: nullable Int = null
228 for parent
in self.parents
do
229 # direct parent is root
230 if parent
.parents
.is_empty
then
233 var depth
= parent
.depth_from_object
+ 1
234 if max_depth
== null then
237 if depth
> max_depth
then max_depth
= depth
241 if max_depth
== null then
248 # Return the longest path from class to root hierarchy
249 private fun path_to_object
: Array[MClass] do
250 var path
= new Array[MClass]
251 var max_dit
: nullable Int = null
252 var max_parent
: nullable MClass = null
253 var parent_path
: nullable Array[MClass] = null
256 var dit
= p
.depth_from_object
257 if max_dit
== null or dit
>= max_dit
then
260 parent_path
= p
.path_to_object
264 if max_parent
!= null and parent_path
!= null then
266 path
.add_all
(parent_path
)
274 private fun is_dui_eligible
: Bool do
275 for parent
in parents
do if parent
.name
!= "Object" then return true
278 private fun is_ccdui_eligible
: Bool do
279 if not is_class
then return false
280 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_class
then return true
283 private fun is_cidui_eligible
: Bool do
284 if not is_class
then return false
285 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
288 private fun is_iidui_eligible
: Bool do
289 if not is_interface
then return false
290 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
293 private fun is_if_eligible
(model
: Model): Bool do return not children
(model
).is_empty
294 private fun is_ccif_eligible
(model
: Model): Bool do
295 if not is_class
then return false
296 for child
in children
(model
) do if child
.is_class
then return true
299 private fun is_icif_eligible
(model
: Model): Bool do
300 if not is_interface
then return false
301 for child
in children
(model
) do if child
.is_class
then return true
304 private fun is_iiif_eligible
(model
: Model): Bool do
305 if not is_interface
then return false
306 for child
in children
(model
) do if child
.is_interface
then return true
312 private fun is_sldui_eligible
: Bool do
313 if is_user_defined
then return false
314 for parent
in parents
do if parent
.name
!= "Object" then return true
317 private fun is_slccdui_eligible
: Bool do
318 if is_user_defined
then return false
319 if not is_class
then return false
320 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_class
then return true
323 private fun is_slcidui_eligible
: Bool do
324 if is_user_defined
then return false
325 if not is_class
then return false
326 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
329 private fun is_sliidui_eligible
: Bool do
330 if is_user_defined
then return false
331 if not is_interface
then return false
332 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
335 private fun is_slif_eligible
(model
: Model): Bool do
336 if is_user_defined
then return false
337 return not children
(model
).is_empty
339 private fun is_slccif_eligible
(model
: Model): Bool do
340 if is_user_defined
then return false
341 if not is_class
then return false
342 for child
in children
(model
) do if child
.is_class
then return true
345 private fun is_slicif_eligible
(model
: Model): Bool do
346 if is_user_defined
then return false
347 if not is_interface
then return false
348 for child
in children
(model
) do if child
.is_class
then return true
351 private fun is_sliiif_eligible
(model
: Model): Bool do
352 if is_user_defined
then return false
353 if not is_interface
then return false
354 for child
in children
(model
) do if child
.is_interface
then return true
360 private fun is_slifsl_eligible
(model
: Model): Bool do
361 if is_user_defined
then return false
362 for child
in children
(model
) do if not child
.is_user_defined
then return true
365 private fun is_slccifsl_eligible
(model
: Model): Bool do
366 if is_user_defined
then return false
367 if is_class
then return false
368 for child
in children
(model
) do if not child
.is_user_defined
and child
.is_class
then return true
371 private fun is_slicifsl_eligible
(model
: Model): Bool do
372 if is_user_defined
then return false
373 if not is_interface
then return false
374 for child
in children
(model
) do if not child
.is_user_defined
and child
.is_class
then return true
377 private fun is_sliiifsl_eligible
(model
: Model): Bool do
378 if is_user_defined
then return false
379 if not is_interface
then return false
380 for child
in children
(model
) do if not child
.is_user_defined
and child
.is_interface
then return true
386 private fun is_slifud_eligible
(model
: Model): Bool do
387 if is_user_defined
then return false
388 for child
in children
(model
) do if child
.is_user_defined
then return true
391 private fun is_slccifud_eligible
(model
: Model): Bool do
392 if is_user_defined
then return false
393 if not is_class
then return false
394 for child
in children
(model
) do if child
.is_user_defined
and child
.is_class
then return true
397 private fun is_slicifud_eligible
(model
: Model): Bool do
398 if is_user_defined
then return false
399 if not is_interface
then return false
400 for child
in children
(model
) do if child
.is_user_defined
and child
.is_class
then return true
403 private fun is_sliiifud_eligible
(model
: Model): Bool do
404 if is_user_defined
then return false
405 if not is_interface
then return false
406 for child
in children
(model
) do if child
.is_user_defined
and child
.is_interface
then return true
412 private fun is_uddui_eligible
: Bool do
413 if not is_user_defined
then return false
414 for parent
in parents
do if parent
.name
!= "Object" then return true
417 private fun is_udccdui_eligible
: Bool do
418 if not is_user_defined
then return false
419 if not is_class
then return false
420 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_class
then return true
423 private fun is_udcidui_eligible
: Bool do
424 if not is_user_defined
then return false
425 if not is_class
then return false
426 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
429 private fun is_udiidui_eligible
: Bool do
430 if not is_user_defined
then return false
431 if not is_interface
then return false
432 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
then return true
435 private fun is_udif_eligible
(model
: Model): Bool do
436 if not is_user_defined
then return false
437 return not children
(model
).is_empty
439 private fun is_udccif_eligible
(model
: Model): Bool do
440 if not is_user_defined
then return false
441 if not is_class
then return false
442 for child
in children
(model
) do if child
.is_class
then return true
445 private fun is_udicif_eligible
(model
: Model): Bool do
446 if not is_user_defined
then return false
447 if not is_interface
then return false
448 for child
in children
(model
) do if child
.is_class
then return true
451 private fun is_udiiif_eligible
(model
: Model): Bool do
452 if not is_user_defined
then return false
453 if not is_interface
then return false
454 for child
in children
(model
) do if child
.is_interface
then return true
460 private fun is_udduisl_eligible
: Bool do
461 if not is_user_defined
then return false
462 for parent
in parents
do if not parent
.is_user_defined
and parent
.name
!= "Object" then return true
465 private fun is_udccduisl_eligible
: Bool do
466 if not is_user_defined
then return false
467 if not is_class
then return false
468 for parent
in parents
do if not parent
.is_user_defined
and parent
.name
!= "Object" and parent
.is_class
then return true
471 private fun is_udciduisl_eligible
: Bool do
472 if not is_user_defined
then return false
473 if not is_class
then return false
474 for parent
in parents
do if not parent
.is_user_defined
and parent
.name
!= "Object" and parent
.is_interface
then return true
477 private fun is_udiiduisl_eligible
: Bool do
478 if not is_user_defined
then return false
479 if not is_interface
then return false
480 for parent
in parents
do if not parent
.is_user_defined
and parent
.name
!= "Object" and parent
.is_interface
then return true
486 private fun is_udduiud_eligible
: Bool do
487 if not is_user_defined
then return false
488 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_user_defined
then return true
491 private fun is_udccduiud_eligible
: Bool do
492 if not is_user_defined
then return false
493 if not is_class
then return false
494 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_class
and parent
.is_user_defined
then return true
497 private fun is_udciduiud_eligible
: Bool do
498 if not is_user_defined
then return false
499 if not is_class
then return false
500 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
and parent
.is_user_defined
then return true
503 private fun is_udiiduiud_eligible
: Bool do
504 if not is_user_defined
then return false
505 if not is_interface
then return false
506 for parent
in parents
do if parent
.name
!= "Object" and parent
.is_interface
and parent
.is_user_defined
then return true
509 private fun is_udifud_eligible
(model
: Model): Bool do
510 if not is_user_defined
then return false
511 return not children
(model
).is_empty
513 private fun is_udccifud_eligible
(model
: Model): Bool do
514 if not is_user_defined
then return false
515 if not is_class
then return false
516 for child
in children
(model
) do if child
.is_user_defined
and child
.is_class
then return true
519 private fun is_udicifud_eligible
(model
: Model): Bool do
520 if not is_user_defined
then return false
521 if not is_interface
then return false
522 for child
in children
(model
) do if child
.is_user_defined
and child
.is_class
then return true
525 private fun is_udiiifud_eligible
(model
: Model): Bool do
526 if not is_user_defined
then return false
527 if not is_interface
then return false
528 for child
in children
(model
) do if child
.is_user_defined
and child
.is_interface
then return true
534 # Print inheritance usage metrics
535 fun compute_inheritance_metrics
(toolcontext
: ToolContext, model
: Model)
537 # global summary metrics
538 var nmd
: Int = 0 # (NMD) Number of Modules
539 var nc
: Int = 0 # (NC) Number of Classes
540 var ni
: Int = 0 # (NI) Number of Interfaces
541 var nac
: Int = 0 # (NAC) Number of Abstract Classes
542 var ngc
: Int = 0 # (NGC) Number of Generic Classes
543 var ngi
: Int = 0 # (NGI) Number of Generic Interfaces
544 # (SL) Std-Lib summary metrics
545 var nmdsl
: Int = 0 # (NMDSL) Number of Modules in Std-Lib
546 var ncsl
: Int = 0 # (NCSL) Number of Classes in Std-Lib
547 var nisl
: Int = 0 # (NISL) Number of Interfaces in Std-Lib
548 var nacsl
: Int = 0 # (NACSL) Number of Abstract Classes in Std-Lib
549 var ngcsl
: Int = 0 # (NGCSL) Number of Generic Classes in Std-Lib
550 var ngisl
: Int = 0 # (NGISL) Number of Generic Interfaces in Std-Lib
551 # (UD) User-Defined summary metrics
552 var nmdud
: Int = 0 # (NMDUD) Number of Modules User Defined
553 var ncud
: Int = 0 # (NCUD) Number of Classes User Defined
554 var niud
: Int = 0 # (NIUD) Number of Interfaces User Defined
555 var nacud
: Int = 0 # (NACUD) Number of Abstract Classes User Defined
556 var ngcud
: Int = 0 # (NGCUD) Number of Generic Classes User Defined
557 var ngiud
: Int = 0 # (NGIUD) Number of Generic Interfaces User Defined
559 # global summary inheritance metrics
560 var dit
= "" # (DIT) Global Depth in Inheritance Tree
561 var dui
= "" # (DUI) Proportion of types that either implement an interface or extend another type other than Object
562 var ccdui
= "" # (CCDUI) Proportion of classes that extend some other class.
563 var cidui
= "" # (CIDUI) Proportion of classes that implement some other interface.
564 var iidui
= "" # (IIDUI) Proportion of interfaces that extend some other interface.
565 var inhf
= "" # (IF) Proportion of types Inherited From, that is, those types that are either extended or implemented
566 var ccif
= "" # (CCIF) Proportion of classes extended by some other class.
567 var icif
= "" # (ICIF) Proportion of interfaces implemented by some other class.
568 var iiif
= "" # (IIIF) Proportion of interfaces extended by some other interface.
570 # (SL -> *) Std-Lib summary inheritance metrics
571 var sldui
= "" # (SLDUI) Proportion of std-lib types that either implement an interface or extend another std-lib type other than Object
572 var slccdui
= "" # (SLCCDUI) Proportion of std-lib classes that extend some other std-lib class.
573 var slcidui
= "" # (SLCIDUI) Proportion of std-lib classes that implement some other std-lib interface.
574 var sliidui
= "" # (SLIIDUI) Proportion of std-lib interfaces that extend some other std-lib interface.
575 var slinhf
= "" # (SLIF) Proportion of SL types Inherited From, that is, those types that are either extended or implemented
576 var slccif
= "" # (SLCCIF) Proportion of SL classes extended by some other class.
577 var slicif
= "" # (SLICIF) Proportion of SL interfaces implemented by some other class.
578 var sliiif
= "" # (SLIIIF) Proportion of SL interfaces extended by some other interface.
580 # (SL -> SL) Std-Lib summary inheritance metrics
581 var slinhfsl
= "" # (SLIFSL) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a SL type
582 var slccifsl
= "" # (SLCCIFSL) Proportion of SL classes extended by some other SL class.
583 var slicifsl
= "" # (SLICIFSL) Proportion of SL interfaces implemented by some other SL class.
584 var sliiifsl
= "" # (SLIIIFSL) Proportion of SL interfaces extended by some other SL interface.
586 # (SL -> UD) Std-Lib summary inheritance metrics
587 var slinhfud
= "" # (SLIFUD) Proportion of SL types Inherited From, that is, those types that are either extended or implemented by a UD type
588 var slccifud
= "" # (SLCCIFUD) Proportion of SL classes extended by some other UD class.
589 var slicifud
= "" # (SLICIFUD) Proportion of SL interfaces implemented by some other UD class.
590 var sliiifud
= "" # (SLIIIFUD) Proportion of SL interfaces extended by some other UD interface.
592 # (UD -> *) User-defined summary inheritance metrics
593 var uddui
= "" # (UDDUI) Proportion user-defined of types that either implement an interface or extend another type
594 var udccdui
= "" # (UDCCDUI) Proportion of user-defined classes that extend some other class.
595 var udcidui
= "" # (UDCIDUI) Proportion of user-defined classes that implement some other interface.
596 var udiidui
= "" # (UDIIDUI) Proportion of user-defined interfaces that extend some other interface.
597 var udinhf
= "" # (UDIF) Proportion of UD types Inherited From, that is, those types that are either extended or implemented
598 var udccif
= "" # (UDCCIF) Proportion of UD classes extended by some other class.
599 var udicif
= "" # (UDICIF) Proportion of UD interfaces implemented by some other class.
600 var udiiif
= "" # (UDIIIF) Proportion of UD interfaces extended by some other interface.
602 # (UD -> SL) User-defined summary inheritance metrics
603 var udduisl
= "" # (UDDUISL) Proportion user-defined of types that either implement an interface or extend another type SL
604 var udccduisl
= "" # (UDCCDUISL) Proportion of user-defined classes that extend some other SL class.
605 var udciduisl
= "" # (UDCIDUISL) Proportion of user-defined classes that implement some other SL interface.
606 var udiiduisl
= "" # (UDIIDUISL) Proportion of user-defined interfaces that extend some other SL interface.
608 # (UD -> UD) User-defined summary inheritance metrics
609 var udduiud
= "" # (UDDUIUD) Proportion user-defined of types that either implement an interface or extend another type user-defined
610 var udccduiud
= "" # (UDCCDUIUD) Proportion of user-defined classes that extend some other user-defined class.
611 var udciduiud
= "" # (UDCIDUIUD) Proportion of user-defined classes that implement some other user-defined interface.
612 var udiiduiud
= "" # (UDIIDUIUD) Proportion of user-defined interfaces that extend some other user-defined interface.
613 var udinhfud
= "" # (UDIFUD) Proportion of UD types Inherited From, that is, those types that are either extended or implemented by another UD type
614 var udccifud
= "" # (UDCCIFUD) Proportion of UD classes extended by some other UD class.
615 var udicifud
= "" # (UDICIFUD) Proportion of UD interfaces implemented by some other UD class.
616 var udiiifud
= "" # (UDIIIFUD) Proportion of UD interfaces extended by some other UD interface.
618 # compute scalar metrics
619 for mclass
in model
.mclasses
do
620 mclass
.compute_scalar_metrics
(model
)
623 # compute summary metrics
625 # compute global summary metrics
626 nmd
= model
.mmodules
.length
627 nc
= model
.extract_classes
(model
.mclasses
).length
628 ni
= model
.extract_interfaces
(model
.mclasses
).length
629 nac
= model
.extract_abstracts
(model
.mclasses
).length
630 ngc
= model
.extract_generics
(model
.extract_classes
(model
.mclasses
)).length
631 ngi
= model
.extract_generics
(model
.extract_interfaces
(model
.mclasses
)).length
632 # compute std-lib summary metrics
633 nmdsl
= model
.extract_stdlib_modules
(model
.mmodules
).length
634 ncsl
= model
.extract_stdlib
(model
.extract_classes
(model
.mclasses
)).length
635 nisl
= model
.extract_stdlib
(model
.extract_interfaces
(model
.mclasses
)).length
636 nacsl
= model
.extract_stdlib
(model
.extract_abstracts
(model
.mclasses
)).length
637 ngcsl
= model
.extract_stdlib
(model
.extract_generics
(model
.extract_classes
(model
.mclasses
))).length
638 ngisl
= model
.extract_stdlib
(model
.extract_generics
(model
.extract_interfaces
(model
.mclasses
))).length
639 # compute user-defined summary metrics
640 nmdud
= model
.extract_user_defined_modules
(model
.mmodules
).length
641 ncud
= model
.extract_user_defined
(model
.extract_classes
(model
.mclasses
)).length
642 niud
= model
.extract_user_defined
(model
.extract_interfaces
(model
.mclasses
)).length
643 nacud
= model
.extract_user_defined
(model
.extract_abstracts
(model
.mclasses
)).length
644 ngcud
= model
.extract_user_defined
(model
.extract_generics
(model
.extract_classes
(model
.mclasses
))).length
645 ngiud
= model
.extract_user_defined
(model
.extract_generics
(model
.extract_interfaces
(model
.mclasses
))).length
647 # compute inheritance summary metrics
662 var slccdui_count
= 0
663 var slcidui_count
= 0
664 var sliidui_count
= 0
672 var slccifsl_count
= 0
673 var slicifsl_count
= 0
674 var sliiifsl_count
= 0
678 var slccifud_count
= 0
679 var slicifud_count
= 0
680 var sliiifud_count
= 0
684 var udccdui_count
= 0
685 var udcidui_count
= 0
686 var udiidui_count
= 0
693 var udduisl_count
= 0
694 var udccduisl_count
= 0
695 var udciduisl_count
= 0
696 var udiiduisl_count
= 0
699 var udduiud_count
= 0
700 var udccduiud_count
= 0
701 var udciduiud_count
= 0
702 var udiiduiud_count
= 0
704 var udccifud_count
= 0
705 var udicifud_count
= 0
706 var udiiifud_count
= 0
708 for mclass
in model
.mclasses
do
712 if mclass
.is_dui_eligible
then dui_count
+= 1
713 if mclass
.is_ccdui_eligible
then ccdui_count
+= 1
714 if mclass
.is_cidui_eligible
then cidui_count
+= 1
715 if mclass
.is_iidui_eligible
then iidui_count
+= 1
716 if mclass
.is_if_eligible
(model
) then if_count
+= 1
717 if mclass
.is_ccif_eligible
(model
) then ccif_count
+= 1
718 if mclass
.is_icif_eligible
(model
) then icif_count
+= 1
719 if mclass
.is_iiif_eligible
(model
) then iiif_count
+= 1
722 if mclass
.is_sldui_eligible
then sldui_count
+= 1
723 if mclass
.is_slccdui_eligible
then slccdui_count
+= 1
724 if mclass
.is_slcidui_eligible
then slcidui_count
+= 1
725 if mclass
.is_sliidui_eligible
then sliidui_count
+= 1
726 if mclass
.is_slif_eligible
(model
) then slif_count
+= 1
727 if mclass
.is_slccif_eligible
(model
) then slccif_count
+= 1
728 if mclass
.is_slicif_eligible
(model
) then slicif_count
+= 1
729 if mclass
.is_sliiif_eligible
(model
) then sliiif_count
+= 1
732 if mclass
.is_slifsl_eligible
(model
) then slifsl_count
+= 1
733 if mclass
.is_slccifsl_eligible
(model
) then slccifsl_count
+= 1
734 if mclass
.is_slicifsl_eligible
(model
) then slicifsl_count
+= 1
735 if mclass
.is_sliiifsl_eligible
(model
) then sliiifsl_count
+= 1
738 if mclass
.is_slifud_eligible
(model
) then slifud_count
+= 1
739 if mclass
.is_slccifud_eligible
(model
) then slccifud_count
+= 1
740 if mclass
.is_slicifud_eligible
(model
) then slicifud_count
+= 1
741 if mclass
.is_sliiifud_eligible
(model
) then sliiifud_count
+= 1
744 if mclass
.is_uddui_eligible
then uddui_count
+= 1
745 if mclass
.is_udccdui_eligible
then udccdui_count
+= 1
746 if mclass
.is_udcidui_eligible
then udcidui_count
+= 1
747 if mclass
.is_udiidui_eligible
then udiidui_count
+= 1
748 if mclass
.is_udif_eligible
(model
) then udif_count
+= 1
749 if mclass
.is_udccif_eligible
(model
) then udccif_count
+= 1
750 if mclass
.is_udicif_eligible
(model
) then udicif_count
+= 1
751 if mclass
.is_udiiif_eligible
(model
) then udiiif_count
+= 1
754 if mclass
.is_udduisl_eligible
then udduisl_count
+= 1
755 if mclass
.is_udccduisl_eligible
then udccduisl_count
+= 1
756 if mclass
.is_udciduisl_eligible
then udciduisl_count
+= 1
757 if mclass
.is_udiiduisl_eligible
then udiiduisl_count
+= 1
760 if mclass
.is_udduiud_eligible
then udduiud_count
+= 1
761 if mclass
.is_udccduiud_eligible
then udccduiud_count
+= 1
762 if mclass
.is_udciduiud_eligible
then udciduiud_count
+= 1
763 if mclass
.is_udiiduiud_eligible
then udiiduiud_count
+= 1
764 if mclass
.is_udifud_eligible
(model
) then udifud_count
+= 1
765 if mclass
.is_udccifud_eligible
(model
) then udccifud_count
+= 1
766 if mclass
.is_udicifud_eligible
(model
) then udicifud_count
+= 1
767 if mclass
.is_udiiifud_eligible
(model
) then udiiifud_count
+= 1
771 dit
= div
(ditsum
, model
.mclasses
.length
)
772 dui
= div
(dui_count
* 100, nc
+ ni
)
773 ccdui
= div
(ccdui_count
* 100, nc
)
774 cidui
= div
(cidui_count
* 100, nc
)
775 iidui
= div
(iidui_count
* 100, ni
)
776 inhf
= div
(if_count
* 100, nc
+ ni
)
777 ccif
= div
(ccif_count
* 100, nc
)
778 icif
= div
(icif_count
* 100, ni
)
779 iiif
= div
(iiif_count
* 100, ni
)
782 sldui
= div
(sldui_count
* 100, ncsl
+ nisl
)
783 slccdui
= div
(slccdui_count
* 100, ncsl
)
784 slcidui
= div
(slcidui_count
* 100, ncsl
)
785 sliidui
= div
(sliidui_count
* 100, nisl
)
786 slinhf
= div
(slif_count
* 100, ncsl
+ nisl
)
787 slccif
= div
(slccif_count
* 100, ncsl
)
788 slicif
= div
(slicif_count
* 100, nisl
)
789 sliiif
= div
(sliiif_count
* 100, nisl
)
792 slinhfsl
= div
(slifsl_count
* 100, ncsl
+ nisl
)
793 slccifsl
= div
(slccifsl_count
* 100, ncsl
)
794 slicifsl
= div
(slicifsl_count
* 100, nisl
)
795 sliiifsl
= div
(sliiifsl_count
* 100, nisl
)
798 slinhfud
= div
(slifud_count
* 100, ncsl
+ nisl
)
799 slccifud
= div
(slccifud_count
* 100, ncsl
)
800 slicifud
= div
(slicifud_count
* 100, nisl
)
801 sliiifud
= div
(sliiifud_count
* 100, nisl
)
804 uddui
= div
(uddui_count
* 100, ncud
+ niud
)
805 udccdui
= div
(udccdui_count
* 100, ncud
)
806 udcidui
= div
(udcidui_count
* 100, ncud
)
807 udiidui
= div
(udiidui_count
* 100, niud
)
808 udinhf
= div
(if_count
* 100, ncud
+ niud
)
809 udccif
= div
(ccif_count
* 100, ncud
)
810 udicif
= div
(icif_count
* 100, niud
)
811 udiiif
= div
(iiif_count
* 100, niud
)
814 udduisl
= div
(udduisl_count
* 100, ncud
+ niud
)
815 udccduisl
= div
(udccduisl_count
* 100, ncud
)
816 udciduisl
= div
(udciduisl_count
* 100, ncud
)
817 udiiduisl
= div
(udiiduisl_count
* 100, niud
)
820 udduiud
= div
(udduiud_count
* 100, ncud
+ niud
)
821 udccduiud
= div
(udccduiud_count
* 100, ncud
)
822 udciduiud
= div
(udciduiud_count
* 100, ncud
)
823 udiiduiud
= div
(udiiduiud_count
* 100, niud
)
824 udinhfud
= div
(udifud_count
* 100, ncud
+ niud
)
825 udccifud
= div
(udccifud_count
* 100, ncud
)
826 udicifud
= div
(udicifud_count
* 100, niud
)
827 udiiifud
= div
(udiiifud_count
* 100, niud
)
830 if toolcontext
.opt_generate_csv
.value
then
832 var summaryCSV
= new CSVDocument(toolcontext
.output_dir
.join_path
("summary_metrics.csv"))
833 summaryCSV
.set_header
("scope", "NMD", "NC", "NI", "NAC", "NGC", "NGI")
834 summaryCSV
.add_line
("global", nmd
, nc
, ni
, nac
, ngc
, ngi
)
835 summaryCSV
.add_line
("std-lib", nmdsl
, ncsl
, nisl
, nacsl
, ngcsl
, ngisl
)
836 summaryCSV
.add_line
("user-defined", nmdud
, ncud
, niud
, nacud
, ngcud
, ngiud
)
839 # inheritance metrics
840 var inheritanceCSV
= new CSVDocument(toolcontext
.output_dir
.join_path
("inheritance_metrics.csv"))
841 inheritanceCSV
.set_header
("scope", "DIT", "DUI", "CCDUI", "CIDUI", "IIDUI", "IF", "CCIF", "ICIF", "IIIF")
842 inheritanceCSV
.add_line
("global", dit
, dui
, ccdui
, cidui
, iidui
, inhf
, ccif
, icif
, iiif
)
843 inheritanceCSV
.add_line
("SL -> *", "", sldui
, slccdui
, slcidui
, sliidui
, slinhf
, slccif
, slicif
, sliiif
)
844 inheritanceCSV
.add_line
("SL -> SL", "", sldui
, slccdui
, slcidui
, sliidui
, slinhfsl
, slccifsl
, slicifsl
, sliiifsl
)
845 inheritanceCSV
.add_line
("SL -> UD", "", 0, 0, 0, 0, slinhfud
, slccifud
, slicifud
, sliiifud
)
846 inheritanceCSV
.add_line
("UD -> *", "", uddui
, udccdui
, udcidui
, udiidui
, udinhf
, udccif
, udicif
, udiiif
)
847 inheritanceCSV
.add_line
("UD -> SL", "", udduisl
, udccduisl
, udciduisl
, udiiduisl
, 0, 0, 0, 0)
848 inheritanceCSV
.add_line
("UD -> UD", "", udduiud
, udccduiud
, udciduiud
, udiiduiud
, udinhfud
, udccifud
, udicifud
, udiiifud
)
852 var scalarCSV
= new CSVDocument(toolcontext
.output_dir
.join_path
("global_scalar_metrics.csv"))
853 var udscalarCSV
= new CSVDocument(toolcontext
.output_dir
.join_path
("ud_scalar_metrics.csv"))
854 scalarCSV
.set_header
("mclass", "type", "DIT", "DITC", "DITI", "NOP", "NOPC", "NOPI", "NOA", "NOAC", "NOAI", "NOC", "NOCC", "NOCI", "NOD", "NODC", "NODI")
855 udscalarCSV
.set_header
("mclass", "type", "DITUD", "DITCUD", "DITIUD", "NOPUD", "NOPCUD", "NOPIUD", "NOAUD", "NOACUD", "NOAIUD", "NOCUD", "NOCCUD", "NOCIUD", "NODUD", "NODCUD", "NODIUD")
856 for mclass
in model
.mclasses
do
857 var name
= mclass
.name
859 if mclass
.is_interface
then typ
= "interface"
860 scalarCSV
.add_line
(name
, typ
, mclass
.dit
, mclass
.ditc
, mclass
.diti
, mclass
.nop
, mclass
.nopc
, mclass
.nopi
, mclass
.noa
, mclass
.noac
, mclass
.noai
, mclass
.noc
, mclass
.nocc
, mclass
.noci
, mclass
.nod
, mclass
.nodc
, mclass
.nodi
)
861 udscalarCSV
.add_line
(name
, typ
, mclass
.ditud
, mclass
.ditcud
, mclass
.ditiud
, mclass
.nopud
, mclass
.nopcud
, mclass
.nopiud
, mclass
.noaud
, mclass
.noacud
, mclass
.noaiud
, mclass
.nocud
, mclass
.noccud
, mclass
.nociud
, mclass
.nodud
, mclass
.nodcud
, mclass
.nodiud
)
867 print
"--- Global Summary metrics ---"
868 print
"(NMD) Number of Modules: {nmd}"
869 print
"(NC) Number of Classes: {nc}"
870 print
"(NI) Number of Interfaces: {ni}"
871 print
"(NAC) Number of Abstract Classes: {nac}"
872 print
"(NGC) Number of Generic Classes: {ngc}"
873 print
"(NGI) Number of Generic Interfaces: {ngi}"
874 print
"--- (SL) Std-Lib Summary metrics ---"
875 print
"(NMDSL) Number of Modules: {nmdsl}"
876 print
"(NCSL) Number of Classes: {ncsl}"
877 print
"(NISL) Number of Interfaces: {nisl}"
878 print
"(NACSL) Number of Abstract Classes: {nacsl}"
879 print
"(NGCSL) Number of Generic Classes: {ngcsl}"
880 print
"(NGISL) Number of Generic Interfaces: {ngisl}"
881 print
"--- (UD) User-Defined Summary metrics ---"
882 print
"(NMDUD) Number of Modules: {nmdud}"
883 print
"(NCUD) Number of Classes: {ncud}"
884 print
"(NIUD) Number of Interfaces: {niud}"
885 print
"(NACUD) Number of Abstract Classes: {nacud}"
886 print
"(NGCUD) Number of Generic Classes: {ngcud}"
887 print
"(NGIUD) Number of Generic Interfaces: {ngiud}"
889 print
"--- Global Inheritance metrics ---"
890 print
"(DIT) Global Depth in Inheritance Tree: {dit}"
891 print
"(DUI) Proportion of types inheriting another type other than Object: {dui}%"
892 print
"(CCDUI) Proportion of classes that extend some other class: {ccdui}%"
893 print
"(CIDUI) Proportion of classes that implement some other interface: {cidui}%"
894 print
"(IIDUI) Proportion of interfaces that extend some other interface: {iidui}%"
895 print
"(IF) Proportion of types Inherited From: {inhf}%"
896 print
"(CCIF) Proportion of classes extended by class: {ccif}%"
897 print
"(ICIF) Proportion of interfaces implemented by class: {icif}%"
898 print
"(IIIF) Proportion of interfaces extended by interface: {iiif}%"
900 print
"--- (SL -> *) Std-Lib Inheritance metrics ---"
901 print
"(SLDUI) Proportion of SL types inheriting another type other than Object: {sldui}%"
902 print
"(SLCCDUI) Proportion of SL classes that extend some other class: {slccdui}%"
903 print
"(SLCIDUI) Proportion of SL classes that implement some other interface: {slcidui}%"
904 print
"(SLIIDUI) Proportion of SL interfaces that extend some other interface: {sliidui}%"
905 print
"(SLIF) Proportion of SL types Inherited From: {slinhf}%"
906 print
"(SLCCIF) Proportion of SL classes extended by class: {slccif}%"
907 print
"(SLICIF) Proportion of SL interfaces implemented by class: {slicif}%"
908 print
"(SLIIIF) Proportion of SL interfaces extended by interface: {sliiif}%"
910 print
"--- (SL -> SL) Std-Lib Inheritance metrics ---"
911 print
"(SLIFSL) Proportion of SL types Inherited From by SL type: {slinhfsl}%"
912 print
"(SLCCIFSL) Proportion of SL classes extended by SL class: {slccifsl}%"
913 print
"(SLICIFSL) Proportion of SL interfaces implemented by SL class: {slicifsl}%"
914 print
"(SLIIIFSL) Proportion of SL interfaces extended by SL interface: {sliiifsl}%"
916 print
"--- (SL->UD) Std-Lib Inheritance metrics ---"
917 print
"(SLIFUD) Proportion of SL types Inherited From by UD type: {slinhfud}%"
918 print
"(SLCCIFUD) Proportion of SL classes extended by UD class: {slccifud}%"
919 print
"(SLICIFUD) Proportion of SL interfaces implemented by UD class: {slicifud}%"
920 print
"(SLIIIFUD) Proportion of SL interfaces extended by UD interface: {sliiifud}%"
922 print
"--- (UD->*) User-Defined Inheritance metrics ---"
923 print
"(UDDUI) Proportion of UD types inheriting another type other than Object: {uddui}%"
924 print
"(UDCCDUI) Proportion of UD classes that extend some other class: {udccdui}%"
925 print
"(UDCIDUI) Proportion of UD classes that implement some other interface: {udcidui}%"
926 print
"(UDIIDUI) Proportion of UD interfaces that extend some other interface: {udiidui}%"
927 print
"(UDIF) Proportion of UD types Inherited From: {udinhf}%"
928 print
"(UDCCIF) Proportion of UD classes extended by class: {udccif}%"
929 print
"(UDICIF) Proportion of UD interfaces implemented by class: {udicif}%"
930 print
"(UDIIIF) Proportion of UD interfaces extended by interface: {udiiif}%"
932 print
"--- (UD -> SL) User-Defined Inheritance metrics ---"
933 print
"(UDDUISL) Proportion of UD types inheriting another type other SL type: {udduisl}%"
934 print
"(UDCCDUISL) Proportion of UD classes that extend some other SL class: {udccduisl}%"
935 print
"(UDCIDUISL) Proportion of UD classes that implement some other SL interface: {udciduisl}%"
936 print
"(UDIIDUISL) Proportion of UD interfaces that extend some other SL interface: {udiiduisl}%"
938 print
"--- (UD -> UD) User-Defined Inheritance metrics ---"
939 print
"(UDDUIUD) Proportion of UD types inheriting another type other UD type: {udduiud}%"
940 print
"(UDCCDUIUD) Proportion of UD classes that extend some other UD class: {udccduiud}%"
941 print
"(UDCIDUIUD) Proportion of UD classes that implement some other UD interface: {udciduiud}%"
942 print
"(UDIIDUIUD) Proportion of UD interfaces that extend some other UD interface: {udiiduiud}%"
943 print
"(UDIFUD) Proportion of UD types Inherited From: {udinhfud}%"
944 print
"(UDCCIFUD) Proportion of UD classes extended by UD class: {udccifud}%"
945 print
"(UDICIFUD) Proportion of UD interfaces implemented by UD class: {udicifud}%"
946 print
"(UDIIIFUD) Proportion of UD interfaces extended by UD interface: {udiiifud}%"
949 # TODO Third-Party metrics
950 # TODO CSV generation
951 # TODO gnu-plot generation